]>
Commit | Line | Data |
---|---|---|
0f5d89e8 A |
1 | // © 2018 and later: Unicode, Inc. and others. |
2 | // License & terms of use: http://www.unicode.org/copyright.html | |
3 | ||
4 | #include "unicode/utypes.h" | |
5 | ||
6 | #if !UCONFIG_NO_FORMATTING | |
7 | ||
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 | |
11 | ||
12 | #include "unicode/unumberformatter.h" | |
13 | #include "unicode/umisc.h" | |
14 | #include "unicode/unum.h" | |
3d1f044b | 15 | #include "cformtst.h" |
0f5d89e8 A |
16 | #include "cintltst.h" |
17 | #include "cmemory.h" | |
18 | ||
19 | static void TestSkeletonFormatToString(void); | |
20 | ||
21 | static void TestSkeletonFormatToFields(void); | |
22 | ||
23 | static void TestExampleCode(void); | |
24 | ||
3d1f044b A |
25 | static void TestFormattedValue(void); |
26 | ||
27 | static void TestSkeletonParseError(void); | |
28 | ||
0f5d89e8 A |
29 | void addUNumberFormatterTest(TestNode** root); |
30 | ||
3d1f044b A |
31 | #define TESTCASE(x) addTest(root, &x, "tsformat/unumberformatter/" #x) |
32 | ||
0f5d89e8 | 33 | void addUNumberFormatterTest(TestNode** root) { |
3d1f044b A |
34 | TESTCASE(TestSkeletonFormatToString); |
35 | TESTCASE(TestSkeletonFormatToFields); | |
36 | TESTCASE(TestExampleCode); | |
37 | TESTCASE(TestFormattedValue); | |
38 | TESTCASE(TestSkeletonParseError); | |
0f5d89e8 A |
39 | } |
40 | ||
41 | ||
42 | #define CAPACITY 30 | |
43 | ||
44 | static void TestSkeletonFormatToString() { | |
45 | UErrorCode ec = U_ZERO_ERROR; | |
46 | UChar buffer[CAPACITY]; | |
47 | UFormattedNumber* result = NULL; | |
48 | ||
49 | // setup: | |
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); | |
55 | ||
56 | // int64 test: | |
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); | |
63 | ||
64 | // double test: | |
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); | |
70 | ||
71 | // decnumber test: | |
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); | |
77 | } | |
78 | ||
79 | // cleanup: | |
80 | unumf_closeResult(result); | |
81 | unumf_close(f); | |
82 | } | |
83 | ||
84 | ||
85 | static void TestSkeletonFormatToFields() { | |
86 | UErrorCode ec = U_ZERO_ERROR; | |
87 | UFieldPositionIterator* ufpositer = NULL; | |
88 | ||
89 | // setup: | |
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)) { | |
97 | ||
98 | // field position test: | |
340931cb | 99 | UFieldPosition ufpos = {UNUM_DECIMAL_SEPARATOR_FIELD, 0, 0}; |
0f5d89e8 A |
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); | |
103 | ||
104 | // field position iterator test: | |
105 | ufpositer = ufieldpositer_open(&ec); | |
106 | if (assertSuccessCheck("Should create iterator without error", &ec, TRUE)) { | |
107 | ||
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}, | |
3d1f044b A |
117 | {UNUM_FRACTION_FIELD, 15, 17}, |
118 | {UNUM_MEASURE_UNIT_FIELD, 18, 19} | |
0f5d89e8 A |
119 | }; |
120 | UFieldPosition actual; | |
340931cb | 121 | for (int32_t i = 0; i < (int32_t)(sizeof(expectedFields) / sizeof(*expectedFields)); i++) { |
0f5d89e8 A |
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) { | |
127 | log_err( | |
128 | "FAIL: iteration %d; expected field %d; got %d\n", i, expected.field, actual.field); | |
129 | } | |
130 | if (expected.beginIndex != actual.beginIndex) { | |
131 | log_err( | |
132 | "FAIL: iteration %d; expected beginIndex %d; got %d\n", | |
133 | i, | |
134 | expected.beginIndex, | |
135 | actual.beginIndex); | |
136 | } | |
137 | if (expected.endIndex != actual.endIndex) { | |
138 | log_err( | |
139 | "FAIL: iteration %d; expected endIndex %d; got %d\n", | |
140 | i, | |
141 | expected.endIndex, | |
142 | actual.endIndex); | |
143 | } | |
144 | } | |
145 | actual.field = ufieldpositer_next(ufpositer, &actual.beginIndex, &actual.endIndex); | |
146 | assertTrue("No more fields; should return a negative index", actual.field < 0); | |
147 | ||
148 | // next field iteration: | |
149 | actual.field = UNUM_GROUPING_SEPARATOR_FIELD; | |
150 | actual.beginIndex = 0; | |
151 | actual.endIndex = 0; | |
152 | int32_t i = 1; | |
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); | |
157 | } | |
158 | assertIntEquals("Should have seen all grouping separators", 4, i); | |
159 | } | |
160 | } | |
161 | ||
162 | // cleanup: | |
163 | unumf_closeResult(uresult); | |
164 | unumf_close(uformatter); | |
165 | ufieldpositer_close(ufpositer); | |
166 | } | |
167 | ||
168 | ||
169 | static void TestExampleCode() { | |
170 | // This is the example code given in unumberformatter.h. | |
171 | ||
172 | // Setup: | |
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); | |
178 | ||
179 | // Format a double: | |
180 | unumf_formatDouble(uformatter, 5142.3, uresult, &ec); | |
181 | if (assertSuccessCheck("There should not be a failure in the example code", &ec, TRUE)) { | |
182 | ||
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); | |
186 | ec = U_ZERO_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); | |
191 | } | |
192 | ||
193 | // Cleanup: | |
194 | unumf_close(uformatter); | |
195 | unumf_closeResult(uresult); | |
196 | uprv_free(buffer); | |
197 | } | |
198 | ||
199 | ||
3d1f044b A |
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); | |
207 | ||
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}}; | |
218 | checkFormattedValue( | |
219 | "FormattedNumber as FormattedValue", | |
220 | fv, | |
221 | u"55.00K", | |
222 | UFIELD_CATEGORY_NUMBER, | |
223 | expectedFieldPositions, | |
224 | UPRV_LENGTHOF(expectedFieldPositions)); | |
225 | } | |
226 | ||
227 | // cleanup: | |
228 | unumf_closeResult(uresult); | |
229 | unumf_close(uformatter); | |
230 | } | |
231 | ||
232 | ||
233 | static void TestSkeletonParseError() { | |
234 | UErrorCode ec = U_ZERO_ERROR; | |
235 | UNumberFormatter* uformatter; | |
236 | UParseError perror; | |
237 | ||
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); | |
242 | ||
243 | // Now test the behavior. | |
244 | ec = U_ZERO_ERROR; | |
245 | uformatter = unumf_openForSkeletonAndLocaleWithError( | |
246 | u".00 measure-unit/typo", -1, "en", &perror, &ec); | |
247 | ||
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); | |
252 | ||
253 | // cleanup: | |
254 | unumf_close(uformatter); | |
255 | } | |
256 | ||
257 | ||
0f5d89e8 | 258 | #endif /* #if !UCONFIG_NO_FORMATTING */ |