1 // © 2018 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 #include "unicode/utypes.h"
6 #if !UCONFIG_NO_FORMATTING
8 // Allow implicit conversion from char16_t* to UnicodeString for this file:
9 // Helpful in toString methods and elsewhere.
10 #define UNISTR_FROM_STRING_EXPLICIT
12 #include "unicode/unumberformatter.h"
13 #include "unicode/umisc.h"
14 #include "unicode/unum.h"
19 static void TestSkeletonFormatToString(void);
21 static void TestSkeletonFormatToFields(void);
23 static void TestExampleCode(void);
25 static void TestFormattedValue(void);
27 static void TestSkeletonParseError(void);
29 void addUNumberFormatterTest(TestNode
** root
);
31 #define TESTCASE(x) addTest(root, &x, "tsformat/unumberformatter/" #x)
33 void addUNumberFormatterTest(TestNode
** root
) {
34 TESTCASE(TestSkeletonFormatToString
);
35 TESTCASE(TestSkeletonFormatToFields
);
36 TESTCASE(TestExampleCode
);
37 TESTCASE(TestFormattedValue
);
38 TESTCASE(TestSkeletonParseError
);
44 static void TestSkeletonFormatToString() {
45 UErrorCode ec
= U_ZERO_ERROR
;
46 UChar buffer
[CAPACITY
];
47 UFormattedNumber
* result
= NULL
;
50 UNumberFormatter
* f
= unumf_openForSkeletonAndLocale(
51 u
"precision-integer currency/USD sign-accounting", -1, "en", &ec
);
52 assertSuccessCheck("Should create without error", &ec
, TRUE
);
53 result
= unumf_openResult(&ec
);
54 assertSuccess("Should create result without error", &ec
);
57 unumf_formatInt(f
, -444444, result
, &ec
);
58 // Missing data will give a U_MISSING_RESOURCE_ERROR here.
59 if (assertSuccessCheck("Should format integer without error", &ec
, TRUE
)) {
60 unumf_resultToString(result
, buffer
, CAPACITY
, &ec
);
61 assertSuccess("Should print string to buffer without error", &ec
);
62 assertUEquals("Should produce expected string result", u
"($444,444)", buffer
);
65 unumf_formatDouble(f
, -5142.3, result
, &ec
);
66 assertSuccess("Should format double without error", &ec
);
67 unumf_resultToString(result
, buffer
, CAPACITY
, &ec
);
68 assertSuccess("Should print string to buffer without error", &ec
);
69 assertUEquals("Should produce expected string result", u
"($5,142)", buffer
);
72 unumf_formatDecimal(f
, "9.876E2", -1, result
, &ec
);
73 assertSuccess("Should format decimal without error", &ec
);
74 unumf_resultToString(result
, buffer
, CAPACITY
, &ec
);
75 assertSuccess("Should print string to buffer without error", &ec
);
76 assertUEquals("Should produce expected string result", u
"$988", buffer
);
80 unumf_closeResult(result
);
85 static void TestSkeletonFormatToFields() {
86 UErrorCode ec
= U_ZERO_ERROR
;
87 UFieldPositionIterator
* ufpositer
= NULL
;
90 UNumberFormatter
* uformatter
= unumf_openForSkeletonAndLocale(
91 u
".00 measure-unit/length-meter sign-always", -1, "en", &ec
);
92 assertSuccessCheck("Should create without error", &ec
, TRUE
);
93 UFormattedNumber
* uresult
= unumf_openResult(&ec
);
94 assertSuccess("Should create result without error", &ec
);
95 unumf_formatInt(uformatter
, 9876543210L, uresult
, &ec
); // "+9,876,543,210.00 m"
96 if (assertSuccessCheck("unumf_formatInt() failed", &ec
, TRUE
)) {
98 // field position test:
99 UFieldPosition ufpos
= {UNUM_DECIMAL_SEPARATOR_FIELD
, 0, 0};
100 unumf_resultNextFieldPosition(uresult
, &ufpos
, &ec
);
101 assertIntEquals("Field position should be correct", 14, ufpos
.beginIndex
);
102 assertIntEquals("Field position should be correct", 15, ufpos
.endIndex
);
104 // field position iterator test:
105 ufpositer
= ufieldpositer_open(&ec
);
106 if (assertSuccessCheck("Should create iterator without error", &ec
, TRUE
)) {
108 unumf_resultGetAllFieldPositions(uresult
, ufpositer
, &ec
);
109 static const UFieldPosition expectedFields
[] = {
110 // Field, begin index, end index
111 {UNUM_SIGN_FIELD
, 0, 1},
112 {UNUM_GROUPING_SEPARATOR_FIELD
, 2, 3},
113 {UNUM_GROUPING_SEPARATOR_FIELD
, 6, 7},
114 {UNUM_GROUPING_SEPARATOR_FIELD
, 10, 11},
115 {UNUM_INTEGER_FIELD
, 1, 14},
116 {UNUM_DECIMAL_SEPARATOR_FIELD
, 14, 15},
117 {UNUM_FRACTION_FIELD
, 15, 17},
118 {UNUM_MEASURE_UNIT_FIELD
, 18, 19}
120 UFieldPosition actual
;
121 for (int32_t i
= 0; i
< (int32_t)(sizeof(expectedFields
) / sizeof(*expectedFields
)); i
++) {
122 // Iterate using the UFieldPosition to hold state...
123 UFieldPosition expected
= expectedFields
[i
];
124 actual
.field
= ufieldpositer_next(ufpositer
, &actual
.beginIndex
, &actual
.endIndex
);
125 assertTrue("Should not return a negative index yet", actual
.field
>= 0);
126 if (expected
.field
!= actual
.field
) {
128 "FAIL: iteration %d; expected field %d; got %d\n", i
, expected
.field
, actual
.field
);
130 if (expected
.beginIndex
!= actual
.beginIndex
) {
132 "FAIL: iteration %d; expected beginIndex %d; got %d\n",
137 if (expected
.endIndex
!= actual
.endIndex
) {
139 "FAIL: iteration %d; expected endIndex %d; got %d\n",
145 actual
.field
= ufieldpositer_next(ufpositer
, &actual
.beginIndex
, &actual
.endIndex
);
146 assertTrue("No more fields; should return a negative index", actual
.field
< 0);
148 // next field iteration:
149 actual
.field
= UNUM_GROUPING_SEPARATOR_FIELD
;
150 actual
.beginIndex
= 0;
153 while (unumf_resultNextFieldPosition(uresult
, &actual
, &ec
)) {
154 UFieldPosition expected
= expectedFields
[i
++];
155 assertIntEquals("Grouping separator begin index", expected
.beginIndex
, actual
.beginIndex
);
156 assertIntEquals("Grouping separator end index", expected
.endIndex
, actual
.endIndex
);
158 assertIntEquals("Should have seen all grouping separators", 4, i
);
163 unumf_closeResult(uresult
);
164 unumf_close(uformatter
);
165 ufieldpositer_close(ufpositer
);
169 static void TestExampleCode() {
170 // This is the example code given in unumberformatter.h.
173 UErrorCode ec
= U_ZERO_ERROR
;
174 UNumberFormatter
* uformatter
= unumf_openForSkeletonAndLocale(u
"precision-integer", -1, "en", &ec
);
175 UFormattedNumber
* uresult
= unumf_openResult(&ec
);
176 UChar
* buffer
= NULL
;
177 assertSuccessCheck("There should not be a failure in the example code", &ec
, TRUE
);
180 unumf_formatDouble(uformatter
, 5142.3, uresult
, &ec
);
181 if (assertSuccessCheck("There should not be a failure in the example code", &ec
, TRUE
)) {
183 // Export the string to a malloc'd buffer:
184 int32_t len
= unumf_resultToString(uresult
, NULL
, 0, &ec
);
185 assertTrue("No buffer yet", ec
== U_BUFFER_OVERFLOW_ERROR
);
187 buffer
= (UChar
*) uprv_malloc((len
+1)*sizeof(UChar
));
188 unumf_resultToString(uresult
, buffer
, len
+1, &ec
);
189 assertSuccess("There should not be a failure in the example code", &ec
);
190 assertUEquals("Should produce expected string result", u
"5,142", buffer
);
194 unumf_close(uformatter
);
195 unumf_closeResult(uresult
);
200 static void TestFormattedValue() {
201 UErrorCode ec
= U_ZERO_ERROR
;
202 UNumberFormatter
* uformatter
= unumf_openForSkeletonAndLocale(
203 u
".00 compact-short", -1, "en", &ec
);
204 assertSuccessCheck("Should create without error", &ec
, TRUE
);
205 UFormattedNumber
* uresult
= unumf_openResult(&ec
);
206 assertSuccess("Should create result without error", &ec
);
208 unumf_formatInt(uformatter
, 55000, uresult
, &ec
); // "55.00 K"
209 if (assertSuccessCheck("Should format without error", &ec
, TRUE
)) {
210 const UFormattedValue
* fv
= unumf_resultAsValue(uresult
, &ec
);
211 assertSuccess("Should convert without error", &ec
);
212 static const UFieldPosition expectedFieldPositions
[] = {
213 // field, begin index, end index
214 {UNUM_INTEGER_FIELD
, 0, 2},
215 {UNUM_DECIMAL_SEPARATOR_FIELD
, 2, 3},
216 {UNUM_FRACTION_FIELD
, 3, 5},
217 {UNUM_COMPACT_FIELD
, 5, 6}};
219 "FormattedNumber as FormattedValue",
222 UFIELD_CATEGORY_NUMBER
,
223 expectedFieldPositions
,
224 UPRV_LENGTHOF(expectedFieldPositions
));
228 unumf_closeResult(uresult
);
229 unumf_close(uformatter
);
233 static void TestSkeletonParseError() {
234 UErrorCode ec
= U_ZERO_ERROR
;
235 UNumberFormatter
* uformatter
;
238 // The UParseError can be null. The following should not segfault.
239 uformatter
= unumf_openForSkeletonAndLocaleWithError(
240 u
".00 measure-unit/typo", -1, "en", NULL
, &ec
);
241 unumf_close(uformatter
);
243 // Now test the behavior.
245 uformatter
= unumf_openForSkeletonAndLocaleWithError(
246 u
".00 measure-unit/typo", -1, "en", &perror
, &ec
);
248 assertIntEquals("Should have set error code", U_NUMBER_SKELETON_SYNTAX_ERROR
, ec
);
249 assertIntEquals("Should have correct skeleton error offset", 17, perror
.offset
);
250 assertUEquals("Should have correct pre context", u
"0 measure-unit/", perror
.preContext
);
251 assertUEquals("Should have correct post context", u
"typo", perror
.postContext
);
254 unumf_close(uformatter
);
258 #endif /* #if !UCONFIG_NO_FORMATTING */