1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /********************************************************************
5 * Copyright (c) 1997-2013, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 ********************************************************************/
9 #include "unicode/utypes.h"
11 #if !UCONFIG_NO_FORMATTING
13 #include "unicode/dcfmtsym.h"
14 #include "unicode/decimfmt.h"
15 #include "unicode/unum.h"
18 void IntlTestDecimalFormatSymbols::runIndexedTest( int32_t index
, UBool exec
, const char* &name
, char* /*par*/ )
21 logln("TestSuite DecimalFormatSymbols:");
24 TESTCASE_AUTO(testSymbols
);
25 TESTCASE_AUTO(testLastResortData
);
26 TESTCASE_AUTO(testDigitSymbols
);
27 TESTCASE_AUTO(testNumberingSystem
);
32 * Test the API of DecimalFormatSymbols; primarily a simple get/set set.
34 void IntlTestDecimalFormatSymbols::testSymbols(/* char *par */)
36 UErrorCode status
= U_ZERO_ERROR
;
38 DecimalFormatSymbols
fr(Locale::getFrench(), status
);
39 if(U_FAILURE(status
)) {
40 errcheckln(status
, "ERROR: Couldn't create French DecimalFormatSymbols - %s", u_errorName(status
));
44 status
= U_ZERO_ERROR
;
45 DecimalFormatSymbols
en(Locale::getEnglish(), status
);
46 if(U_FAILURE(status
)) {
47 errcheckln(status
, "ERROR: Couldn't create English DecimalFormatSymbols - %s", u_errorName(status
));
51 if(en
== fr
|| ! (en
!= fr
) ) {
52 errln("ERROR: English DecimalFormatSymbols equal to French");
55 // just do some VERY basic tests to make sure that get/set work
57 UnicodeString zero
= en
.getSymbol(DecimalFormatSymbols::kZeroDigitSymbol
);
58 fr
.setSymbol(DecimalFormatSymbols::kZeroDigitSymbol
, zero
);
59 if(fr
.getSymbol(DecimalFormatSymbols::kZeroDigitSymbol
) != en
.getSymbol(DecimalFormatSymbols::kZeroDigitSymbol
)) {
60 errln("ERROR: get/set ZeroDigit failed");
63 UnicodeString group
= en
.getSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol
);
64 fr
.setSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol
, group
);
65 if(fr
.getSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol
) != en
.getSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol
)) {
66 errln("ERROR: get/set GroupingSeparator failed");
69 UnicodeString decimal
= en
.getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol
);
70 fr
.setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol
, decimal
);
71 if(fr
.getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol
) != en
.getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol
)) {
72 errln("ERROR: get/set DecimalSeparator failed");
75 UnicodeString perMill
= en
.getSymbol(DecimalFormatSymbols::kPerMillSymbol
);
76 fr
.setSymbol(DecimalFormatSymbols::kPerMillSymbol
, perMill
);
77 if(fr
.getSymbol(DecimalFormatSymbols::kPerMillSymbol
) != en
.getSymbol(DecimalFormatSymbols::kPerMillSymbol
)) {
78 errln("ERROR: get/set PerMill failed");
81 UnicodeString percent
= en
.getSymbol(DecimalFormatSymbols::kPercentSymbol
);
82 fr
.setSymbol(DecimalFormatSymbols::kPercentSymbol
, percent
);
83 if(fr
.getSymbol(DecimalFormatSymbols::kPercentSymbol
) != en
.getSymbol(DecimalFormatSymbols::kPercentSymbol
)) {
84 errln("ERROR: get/set Percent failed");
87 UnicodeString
digit(en
.getSymbol(DecimalFormatSymbols::kDigitSymbol
));
88 fr
.setSymbol(DecimalFormatSymbols::kDigitSymbol
, digit
);
89 if(fr
.getSymbol(DecimalFormatSymbols::kDigitSymbol
) != en
.getSymbol(DecimalFormatSymbols::kDigitSymbol
)) {
90 errln("ERROR: get/set Percent failed");
93 UnicodeString patternSeparator
= en
.getSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol
);
94 fr
.setSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol
, patternSeparator
);
95 if(fr
.getSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol
) != en
.getSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol
)) {
96 errln("ERROR: get/set PatternSeparator failed");
99 UnicodeString
infinity(en
.getSymbol(DecimalFormatSymbols::kInfinitySymbol
));
100 fr
.setSymbol(DecimalFormatSymbols::kInfinitySymbol
, infinity
);
101 UnicodeString
infinity2(fr
.getSymbol(DecimalFormatSymbols::kInfinitySymbol
));
102 if(infinity
!= infinity2
) {
103 errln("ERROR: get/set Infinity failed");
106 UnicodeString
nan(en
.getSymbol(DecimalFormatSymbols::kNaNSymbol
));
107 fr
.setSymbol(DecimalFormatSymbols::kNaNSymbol
, nan
);
108 UnicodeString
nan2(fr
.getSymbol(DecimalFormatSymbols::kNaNSymbol
));
110 errln("ERROR: get/set NaN failed");
113 UnicodeString minusSign
= en
.getSymbol(DecimalFormatSymbols::kMinusSignSymbol
);
114 fr
.setSymbol(DecimalFormatSymbols::kMinusSignSymbol
, minusSign
);
115 if(fr
.getSymbol(DecimalFormatSymbols::kMinusSignSymbol
) != en
.getSymbol(DecimalFormatSymbols::kMinusSignSymbol
)) {
116 errln("ERROR: get/set MinusSign failed");
119 UnicodeString
exponential(en
.getSymbol(DecimalFormatSymbols::kExponentialSymbol
));
120 fr
.setSymbol(DecimalFormatSymbols::kExponentialSymbol
, exponential
);
121 if(fr
.getSymbol(DecimalFormatSymbols::kExponentialSymbol
) != en
.getSymbol(DecimalFormatSymbols::kExponentialSymbol
)) {
122 errln("ERROR: get/set Exponential failed");
125 // Test get currency spacing before the currency.
126 status
= U_ZERO_ERROR
;
127 for (int32_t i
= 0; i
< (int32_t)UNUM_CURRENCY_SPACING_COUNT
; i
++) {
128 UnicodeString enCurrencyPattern
= en
.getPatternForCurrencySpacing(
129 (UCurrencySpacing
)i
, TRUE
, status
);
130 if(U_FAILURE(status
)) {
131 errln("Error: cannot get CurrencyMatch for locale:en");
132 status
= U_ZERO_ERROR
;
134 UnicodeString frCurrencyPattern
= fr
.getPatternForCurrencySpacing(
135 (UCurrencySpacing
)i
, TRUE
, status
);
136 if(U_FAILURE(status
)) {
137 errln("Error: cannot get CurrencyMatch for locale:fr");
139 if (enCurrencyPattern
!= frCurrencyPattern
) {
140 errln("ERROR: get CurrencySpacing failed");
143 // Test get currencySpacing after the currency.
144 status
= U_ZERO_ERROR
;
145 for (int32_t i
= 0; i
< UNUM_CURRENCY_SPACING_COUNT
; i
++) {
146 UnicodeString enCurrencyPattern
= en
.getPatternForCurrencySpacing(
147 (UCurrencySpacing
)i
, FALSE
, status
);
148 if(U_FAILURE(status
)) {
149 errln("Error: cannot get CurrencyMatch for locale:en");
150 status
= U_ZERO_ERROR
;
152 UnicodeString frCurrencyPattern
= fr
.getPatternForCurrencySpacing(
153 (UCurrencySpacing
)i
, FALSE
, status
);
154 if(U_FAILURE(status
)) {
155 errln("Error: cannot get CurrencyMatch for locale:fr");
157 if (enCurrencyPattern
!= frCurrencyPattern
) {
158 errln("ERROR: get CurrencySpacing failed");
161 // Test set curerncySpacing APIs
162 status
= U_ZERO_ERROR
;
163 UnicodeString dash
= UnicodeString("-");
164 en
.setPatternForCurrencySpacing(UNUM_CURRENCY_INSERT
, TRUE
, dash
);
165 UnicodeString enCurrencyInsert
= en
.getPatternForCurrencySpacing(
166 UNUM_CURRENCY_INSERT
, TRUE
, status
);
167 if (dash
!= enCurrencyInsert
) {
168 errln("Error: Failed to setCurrencyInsert for locale:en");
171 status
= U_ZERO_ERROR
;
172 DecimalFormatSymbols
foo(status
);
174 DecimalFormatSymbols
bar(foo
);
178 if(en
!= fr
|| foo
!= bar
) {
179 errln("ERROR: Copy Constructor or Assignment failed");
182 // test get/setSymbol()
183 if((int) UNUM_FORMAT_SYMBOL_COUNT
!= (int) DecimalFormatSymbols::kFormatSymbolCount
) {
184 errln("unum.h and decimfmt.h have inconsistent numbers of format symbols!");
189 for(i
= 0; i
< (int)DecimalFormatSymbols::kFormatSymbolCount
; ++i
) {
190 foo
.setSymbol((DecimalFormatSymbols::ENumberFormatSymbol
)i
, UnicodeString((UChar32
)(0x10330 + i
)));
192 for(i
= 0; i
< (int)DecimalFormatSymbols::kFormatSymbolCount
; ++i
) {
193 if(foo
.getSymbol((DecimalFormatSymbols::ENumberFormatSymbol
)i
) != UnicodeString((UChar32
)(0x10330 + i
))) {
194 errln("get/setSymbol did not roundtrip, got " +
195 foo
.getSymbol((DecimalFormatSymbols::ENumberFormatSymbol
)i
) +
197 UnicodeString((UChar32
)(0x10330 + i
)));
201 DecimalFormatSymbols
sym(Locale::getUS(), status
);
203 UnicodeString
customDecSeperator("S");
204 Verify(34.5, u
"00.00", sym
, u
"34.50");
205 sym
.setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol
, customDecSeperator
);
206 Verify(34.5, u
"00.00", sym
, u
"34S50");
207 sym
.setSymbol(DecimalFormatSymbols::kPercentSymbol
, u
"P");
208 Verify(34.5, u
"00 %", sym
, u
"3450 P");
209 sym
.setSymbol(DecimalFormatSymbols::kCurrencySymbol
, u
"D");
210 Verify(34.5, u
"\u00a4##.##", sym
, u
"D34.5"); // match ICU 61 behavior
211 sym
.setSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol
, u
"|");
212 Verify(3456.5, u
"0,000.##", sym
, u
"3|456S5");
216 void IntlTestDecimalFormatSymbols::testLastResortData() {
217 IcuTestErrorCode
errorCode(*this, "testLastResortData");
218 LocalPointer
<DecimalFormatSymbols
> lastResort(
219 DecimalFormatSymbols::createWithLastResortData(errorCode
));
220 if(errorCode
.errIfFailureAndReset("DecimalFormatSymbols::createWithLastResortData() failed")) {
223 DecimalFormatSymbols
root(Locale::getRoot(), errorCode
);
224 if(errorCode
.errDataIfFailureAndReset("DecimalFormatSymbols(root) failed")) {
227 // Note: It is not necessary that the last resort data matches the root locale,
228 // but it seems weird if most symbols did not match.
229 // Also, one purpose for calling operator==() is to find uninitialized memory in a debug build.
230 if(*lastResort
== root
) {
231 errln("DecimalFormatSymbols last resort data unexpectedly matches root");
233 // Here we adjust for expected differences.
234 assertEquals("last-resort grouping separator",
235 "", lastResort
->getSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol
));
236 lastResort
->setSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol
, ",");
237 assertEquals("last-resort monetary grouping separator",
238 "", lastResort
->getSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol
));
239 lastResort
->setSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol
, ",");
240 assertEquals("last-resort NaN",
241 UnicodeString((UChar
)0xfffd), lastResort
->getSymbol(DecimalFormatSymbols::kNaNSymbol
));
242 lastResort
->setSymbol(DecimalFormatSymbols::kNaNSymbol
, "NaN");
243 // Check that now all of the symbols match root.
244 for(int32_t i
= 0; i
< DecimalFormatSymbols::kFormatSymbolCount
; ++i
) {
245 DecimalFormatSymbols::ENumberFormatSymbol e
= (DecimalFormatSymbols::ENumberFormatSymbol
)i
;
246 assertEquals("last-resort symbol vs. root", root
.getSymbol(e
), lastResort
->getSymbol(e
));
248 // Also, the CurrencySpacing patterns are empty in the last resort instance,
250 Verify(1234567.25, "#,##0.##", *lastResort
, "1,234,567.25");
253 void IntlTestDecimalFormatSymbols::testDigitSymbols() {
254 // This test does more in ICU4J than in ICU4C right now.
255 // In ICU4C, it is basically just a test for codePointZero and getConstDigitSymbol.
256 UChar defZero
= u
'0';
257 UChar32 osmanyaZero
= U
'\U000104A0';
258 static const UChar
* osmanyaDigitStrings
[] = {
259 u
"\U000104A0", u
"\U000104A1", u
"\U000104A2", u
"\U000104A3", u
"\U000104A4",
260 u
"\U000104A5", u
"\U000104A6", u
"\U000104A7", u
"\U000104A8", u
"\U000104A9"
263 IcuTestErrorCode
status(*this, "testDigitSymbols()");
264 DecimalFormatSymbols
symbols(Locale("en"), status
);
266 if (defZero
!= symbols
.getCodePointZero()) {
267 errln("ERROR: Code point zero be ASCII 0");
269 for (int32_t i
=0; i
<=9; i
++) {
270 assertEquals(UnicodeString("i. ASCII Digit at index ") + Int64ToUnicodeString(i
),
271 UnicodeString(u
'0' + i
),
272 symbols
.getConstDigitSymbol(i
));
275 for (int32_t i
=0; i
<=9; i
++) {
276 DecimalFormatSymbols::ENumberFormatSymbol key
=
278 ? DecimalFormatSymbols::kZeroDigitSymbol
279 : static_cast<DecimalFormatSymbols::ENumberFormatSymbol
>
280 (DecimalFormatSymbols::kOneDigitSymbol
+ i
- 1);
281 symbols
.setSymbol(key
, UnicodeString(osmanyaDigitStrings
[i
]), FALSE
);
283 // NOTE: in ICU4J, the calculation of codePointZero is smarter;
284 // in ICU4C, it is more conservative and is only set if propogateDigits is true.
285 if (-1 != symbols
.getCodePointZero()) {
286 errln("ERROR: Code point zero be invalid");
288 for (int32_t i
=0; i
<=9; i
++) {
289 assertEquals(UnicodeString("ii. Osmanya digit at index ") + Int64ToUnicodeString(i
),
290 UnicodeString(osmanyaDigitStrings
[i
]),
291 symbols
.getConstDigitSymbol(i
));
294 // Check Osmanya codePointZero
296 DecimalFormatSymbols::kZeroDigitSymbol
,
297 UnicodeString(osmanyaDigitStrings
[0]), TRUE
);
298 if (osmanyaZero
!= symbols
.getCodePointZero()) {
299 errln("ERROR: Code point zero be Osmanya code point zero");
301 for (int32_t i
=0; i
<=9; i
++) {
302 assertEquals(UnicodeString("iii. Osmanya digit at index ") + Int64ToUnicodeString(i
),
303 UnicodeString(osmanyaDigitStrings
[i
]),
304 symbols
.getConstDigitSymbol(i
));
308 DecimalFormatSymbols
copy(symbols
);
309 if (osmanyaZero
!= copy
.getCodePointZero()) {
310 errln("ERROR: Code point zero be Osmanya code point zero");
312 for (int32_t i
=0; i
<=9; i
++) {
313 assertEquals(UnicodeString("iv. After copy at index ") + Int64ToUnicodeString(i
),
314 UnicodeString(osmanyaDigitStrings
[i
]),
315 copy
.getConstDigitSymbol(i
));
318 // Check when loaded from resource bundle
319 DecimalFormatSymbols
fromData(Locale("en@numbers=osma"), status
);
320 if (osmanyaZero
!= fromData
.getCodePointZero()) {
321 errln("ERROR: Code point zero be Osmanya code point zero");
323 for (int32_t i
=0; i
<=9; i
++) {
324 assertEquals(UnicodeString("v. Resource bundle at index ") + Int64ToUnicodeString(i
),
325 UnicodeString(osmanyaDigitStrings
[i
]),
326 fromData
.getConstDigitSymbol(i
));
329 // Setting a digit somewhere in the middle should invalidate codePointZero
330 symbols
.setSymbol(DecimalFormatSymbols::kOneDigitSymbol
, u
"foo", FALSE
);
331 if (-1 != symbols
.getCodePointZero()) {
332 errln("ERROR: Code point zero be invalid");
335 // Reset digits to Latin
337 DecimalFormatSymbols::kZeroDigitSymbol
,
338 UnicodeString(defZero
));
339 if (defZero
!= symbols
.getCodePointZero()) {
340 errln("ERROR: Code point zero be ASCII 0");
342 for (int32_t i
=0; i
<=9; i
++) {
343 assertEquals(UnicodeString("vi. ASCII Digit at index ") + Int64ToUnicodeString(i
),
344 UnicodeString(u
'0' + i
),
345 symbols
.getConstDigitSymbol(i
));
349 void IntlTestDecimalFormatSymbols::testNumberingSystem() {
350 IcuTestErrorCode
errorCode(*this, "testNumberingSystem");
354 const char16_t* expected1
; // Expected number format string
355 const char16_t* expected2
; // Expected pattern separator
357 static const testcase cases
[] = {
358 {"en", "latn", u
"1,234.56", u
"%"},
359 {"en", "arab", u
"١٬٢٣٤٫٥٦", u
"٪\u061C"},
360 {"en", "mathsanb", u
"𝟭,𝟮𝟯𝟰.𝟱𝟲", u
"%"},
361 {"en", "mymr", u
"၁,၂၃၄.၅၆", u
"%"},
362 {"my", "latn", u
"1,234.56", u
"%"},
363 {"my", "arab", u
"١٬٢٣٤٫٥٦", u
"٪\u061C"},
364 {"my", "mathsanb", u
"𝟭,𝟮𝟯𝟰.𝟱𝟲", u
"%"},
365 {"my", "mymr", u
"၁,၂၃၄.၅၆", u
"%"},
366 {"ar", "latn", u
"1,234.56", u
"\u200E%\u200E"},
367 {"ar", "arab", u
"١٬٢٣٤٫٥٦", u
"٪\u061C"},
368 {"en@numbers=thai", "mymr", u
"၁,၂၃၄.၅၆", u
"%"}, // conflicting numbering system
371 for (int i
=0; i
<8; i
++) {
372 testcase cas
= cases
[i
];
373 Locale
loc(cas
.locid
);
374 LocalPointer
<NumberingSystem
> ns(NumberingSystem::createInstanceByName(cas
.nsname
, errorCode
));
375 if (errorCode
.errDataIfFailureAndReset("NumberingSystem failed")) {
378 UnicodeString
expected1(cas
.expected1
);
379 UnicodeString
expected2(cas
.expected2
);
380 DecimalFormatSymbols
dfs(loc
, *ns
, errorCode
);
381 if (errorCode
.errDataIfFailureAndReset("DecimalFormatSymbols failed")) {
384 Verify(1234.56, "#,##0.##", dfs
, expected1
);
385 // The percent sign differs by numbering system.
386 UnicodeString actual2
= dfs
.getSymbol(DecimalFormatSymbols::kPercentSymbol
);
387 assertEquals((UnicodeString
) "Percent sign with " + cas
.locid
+ " and " + cas
.nsname
,
393 void IntlTestDecimalFormatSymbols::Verify(double value
, const UnicodeString
& pattern
,
394 const DecimalFormatSymbols
&sym
, const UnicodeString
& expected
){
395 UErrorCode status
= U_ZERO_ERROR
;
396 DecimalFormat
df(pattern
, sym
, status
);
397 if(U_FAILURE(status
)){
398 errln("ERROR: construction of decimal format failed - %s", u_errorName(status
));
400 UnicodeString buffer
;
401 FieldPosition
pos(FieldPosition::DONT_CARE
);
402 buffer
= df
.format(value
, buffer
, pos
);
403 if(buffer
!= expected
){
404 errln((UnicodeString
)"ERROR: format() returns wrong result\n Expected " +
405 expected
+ ", Got " + buffer
);
409 #endif /* #if !UCONFIG_NO_FORMATTING */