]>
Commit | Line | Data |
---|---|---|
f3c0d7a5 A |
1 | // © 2016 and later: Unicode, Inc. and others. |
2 | // License & terms of use: http://www.unicode.org/copyright.html | |
51004dcb A |
3 | /* |
4 | ******************************************************************************* | |
5 | * | |
2ca993e8 | 6 | * Copyright (C) 2012-2016, International Business Machines |
51004dcb A |
7 | * Corporation and others. All Rights Reserved. |
8 | * | |
9 | ******************************************************************************* | |
10 | * file name: listformattertest.cpp | |
f3c0d7a5 | 11 | * encoding: UTF-8 |
51004dcb A |
12 | * tab size: 8 (not used) |
13 | * indentation:4 | |
14 | * | |
15 | * created on: 2012aug27 | |
16 | * created by: Umesh P. Nair | |
17 | */ | |
18 | ||
19 | #include "listformattertest.h" | |
3d1f044b A |
20 | #include "unicode/ulistformatter.h" |
21 | #include "cmemory.h" | |
51004dcb A |
22 | #include <string.h> |
23 | ||
3d1f044b A |
24 | #if !UCONFIG_NO_FORMATTING |
25 | ||
340931cb A |
26 | void ListFormatterTest::runIndexedTest(int32_t index, UBool exec, |
27 | const char* &name, char* /*par */) { | |
28 | TESTCASE_AUTO_BEGIN; | |
29 | TESTCASE_AUTO(TestRoot); | |
30 | TESTCASE_AUTO(TestBogus); | |
31 | TESTCASE_AUTO(TestEnglish); | |
32 | TESTCASE_AUTO(TestEnglishUS); | |
33 | TESTCASE_AUTO(TestRussian); | |
34 | TESTCASE_AUTO(TestMalayalam); | |
35 | TESTCASE_AUTO(TestZulu); | |
36 | TESTCASE_AUTO(TestOutOfOrderPatterns); | |
37 | TESTCASE_AUTO(Test9946); | |
38 | TESTCASE_AUTO(TestEnglishGB); | |
39 | TESTCASE_AUTO(TestNynorsk); | |
40 | TESTCASE_AUTO(TestChineseTradHK); | |
41 | TESTCASE_AUTO(TestFieldPositionIteratorWontCrash); | |
42 | TESTCASE_AUTO(TestFieldPositionIteratorWith1Item); | |
43 | TESTCASE_AUTO(TestFieldPositionIteratorWith1ItemAndDataBefore); | |
44 | TESTCASE_AUTO(TestFieldPositionIteratorWith2Items); | |
45 | TESTCASE_AUTO(TestFieldPositionIteratorWith2ItemsAndDataBefore); | |
46 | TESTCASE_AUTO(TestFieldPositionIteratorWith2ItemsPatternShift); | |
47 | TESTCASE_AUTO(TestFieldPositionIteratorWith3Items); | |
48 | TESTCASE_AUTO(TestFieldPositionIteratorWith3ItemsAndDataBefore); | |
49 | TESTCASE_AUTO(TestFieldPositionIteratorWith3ItemsPatternShift); | |
50 | TESTCASE_AUTO(TestFormattedValue); | |
51 | TESTCASE_AUTO(TestDifferentStyles); | |
52 | TESTCASE_AUTO(TestBadStylesFail); | |
53 | TESTCASE_AUTO(TestCreateStyled); | |
54 | TESTCASE_AUTO(TestContextual); | |
55 | TESTCASE_AUTO_END; | |
56 | } | |
57 | ||
3d1f044b A |
58 | namespace { |
59 | const char* attrString(int32_t attrId) { | |
60 | switch (attrId) { | |
61 | case ULISTFMT_LITERAL_FIELD: return "literal"; | |
62 | case ULISTFMT_ELEMENT_FIELD: return "element"; | |
63 | default: return "xxx"; | |
64 | } | |
65 | } | |
66 | } // namespace | |
67 | ||
68 | void ListFormatterTest::ExpectPositions(FieldPositionIterator& iter, | |
69 | int32_t *values, int32_t tupleCount) { | |
70 | UBool found[10]; | |
71 | FieldPosition fp; | |
72 | if (tupleCount > 10) { | |
73 | assertTrue("internal error, tupleCount too large", FALSE); | |
74 | } else { | |
75 | for (int i = 0; i < tupleCount; ++i) { | |
76 | found[i] = FALSE; | |
77 | } | |
78 | } | |
79 | while (iter.next(fp)) { | |
80 | UBool ok = FALSE; | |
81 | int32_t id = fp.getField(); | |
82 | int32_t start = fp.getBeginIndex(); | |
83 | int32_t limit = fp.getEndIndex(); | |
84 | char buf[128]; | |
85 | sprintf(buf, "%24s %3d %3d %3d", attrString(id), id, start, limit); | |
86 | logln(buf); | |
87 | for (int i = 0; i < tupleCount; ++i) { | |
88 | if (found[i]) { | |
89 | continue; | |
90 | } | |
91 | if (values[i*3] == id && values[i*3+1] == start && values[i*3+2] == limit) { | |
92 | found[i] = ok = TRUE; | |
93 | break; | |
94 | } | |
95 | } | |
96 | assertTrue((UnicodeString)"found [" + attrString(id) + "," + start + "," + limit + "]", ok); | |
97 | } | |
98 | // check that all were found | |
99 | UBool ok = TRUE; | |
100 | for (int i = 0; i < tupleCount; ++i) { | |
101 | if (!found[i]) { | |
102 | ok = FALSE; | |
103 | assertTrue((UnicodeString) "missing [" + attrString(values[i*3]) + "," + values[i*3+1] + | |
104 | "," + values[i*3+2] + "]", found[i]); | |
105 | } | |
106 | } | |
107 | assertTrue("no expected values were missing", ok); | |
108 | } | |
109 | ||
51004dcb A |
110 | ListFormatterTest::ListFormatterTest() : |
111 | prefix("Prefix: ", -1, US_INV), | |
112 | one("Alice", -1, US_INV), two("Bob", -1, US_INV), | |
113 | three("Charlie", -1, US_INV), four("Delta", -1, US_INV) { | |
114 | } | |
115 | ||
116 | void ListFormatterTest::CheckFormatting(const ListFormatter* formatter, UnicodeString data[], int32_t dataSize, | |
3d1f044b | 117 | const UnicodeString& expected_result, const char* testName) { |
51004dcb | 118 | UnicodeString actualResult(prefix); |
3d1f044b | 119 | IcuTestErrorCode errorCode(*this, testName); |
51004dcb A |
120 | formatter->format(data, dataSize, actualResult, errorCode); |
121 | UnicodeString expectedStringWithPrefix = prefix + expected_result; | |
122 | if (expectedStringWithPrefix != actualResult) { | |
123 | errln(UnicodeString("Expected: |") + expectedStringWithPrefix + "|, Actual: |" + actualResult + "|"); | |
124 | } | |
125 | } | |
126 | ||
127 | void ListFormatterTest::CheckFourCases(const char* locale_string, UnicodeString one, UnicodeString two, | |
3d1f044b A |
128 | UnicodeString three, UnicodeString four, UnicodeString results[4], const char* testName) { |
129 | IcuTestErrorCode errorCode(*this, testName); | |
51004dcb A |
130 | LocalPointer<ListFormatter> formatter(ListFormatter::createInstance(Locale(locale_string), errorCode)); |
131 | if (U_FAILURE(errorCode)) { | |
132 | dataerrln("ListFormatter::createInstance(Locale(\"%s\"), errorCode) failed in CheckFourCases: %s", locale_string, u_errorName(errorCode)); | |
133 | return; | |
134 | } | |
135 | UnicodeString input1[] = {one}; | |
3d1f044b | 136 | CheckFormatting(formatter.getAlias(), input1, 1, results[0], testName); |
51004dcb A |
137 | |
138 | UnicodeString input2[] = {one, two}; | |
3d1f044b | 139 | CheckFormatting(formatter.getAlias(), input2, 2, results[1], testName); |
51004dcb A |
140 | |
141 | UnicodeString input3[] = {one, two, three}; | |
3d1f044b | 142 | CheckFormatting(formatter.getAlias(), input3, 3, results[2], testName); |
51004dcb A |
143 | |
144 | UnicodeString input4[] = {one, two, three, four}; | |
3d1f044b | 145 | CheckFormatting(formatter.getAlias(), input4, 4, results[3], testName); |
51004dcb A |
146 | } |
147 | ||
148 | UBool ListFormatterTest::RecordFourCases(const Locale& locale, UnicodeString one, UnicodeString two, | |
3d1f044b A |
149 | UnicodeString three, UnicodeString four, UnicodeString results[4], const char* testName) { |
150 | IcuTestErrorCode errorCode(*this, testName); | |
51004dcb A |
151 | LocalPointer<ListFormatter> formatter(ListFormatter::createInstance(locale, errorCode)); |
152 | if (U_FAILURE(errorCode)) { | |
153 | dataerrln("ListFormatter::createInstance(\"%s\", errorCode) failed in RecordFourCases: %s", locale.getName(), u_errorName(errorCode)); | |
154 | return FALSE; | |
155 | } | |
156 | UnicodeString input1[] = {one}; | |
157 | formatter->format(input1, 1, results[0], errorCode); | |
158 | UnicodeString input2[] = {one, two}; | |
159 | formatter->format(input2, 2, results[1], errorCode); | |
160 | UnicodeString input3[] = {one, two, three}; | |
161 | formatter->format(input3, 3, results[2], errorCode); | |
162 | UnicodeString input4[] = {one, two, three, four}; | |
163 | formatter->format(input4, 4, results[3], errorCode); | |
164 | if (U_FAILURE(errorCode)) { | |
165 | errln("RecordFourCases failed: %s", u_errorName(errorCode)); | |
166 | return FALSE; | |
167 | } | |
168 | return TRUE; | |
169 | } | |
170 | ||
171 | void ListFormatterTest::TestRoot() { | |
172 | UnicodeString results[4] = { | |
173 | one, | |
174 | one + ", " + two, | |
175 | one + ", " + two + ", " + three, | |
176 | one + ", " + two + ", " + three + ", " + four | |
177 | }; | |
178 | ||
3d1f044b | 179 | CheckFourCases("", one, two, three, four, results, "TestRoot()"); |
51004dcb A |
180 | } |
181 | ||
182 | // Bogus locale should fallback to root. | |
183 | void ListFormatterTest::TestBogus() { | |
184 | UnicodeString results[4]; | |
3d1f044b A |
185 | if (RecordFourCases(Locale::getDefault(), one, two, three, four, results, "TestBogus()")) { |
186 | CheckFourCases("ex_PY", one, two, three, four, results, "TestBogus()"); | |
51004dcb A |
187 | } |
188 | } | |
189 | ||
190 | // Formatting in English. | |
191 | // "and" is used before the last element, and all elements up to (and including) the penultimate are followed by a comma. | |
192 | void ListFormatterTest::TestEnglish() { | |
193 | UnicodeString results[4] = { | |
194 | one, | |
195 | one + " and " + two, | |
196 | one + ", " + two + ", and " + three, | |
197 | one + ", " + two + ", " + three + ", and " + four | |
198 | }; | |
199 | ||
3d1f044b | 200 | CheckFourCases("en", one, two, three, four, results, "TestEnglish()"); |
51004dcb A |
201 | } |
202 | ||
57a6839d | 203 | void ListFormatterTest::Test9946() { |
3d1f044b | 204 | IcuTestErrorCode errorCode(*this, "Test9946()"); |
57a6839d A |
205 | LocalPointer<ListFormatter> formatter(ListFormatter::createInstance(Locale("en"), errorCode)); |
206 | if (U_FAILURE(errorCode)) { | |
207 | dataerrln( | |
208 | "ListFormatter::createInstance(Locale(\"en\"), errorCode) failed in Test9946: %s", | |
209 | u_errorName(errorCode)); | |
210 | return; | |
211 | } | |
212 | UnicodeString data[3] = {"{0}", "{1}", "{2}"}; | |
213 | UnicodeString actualResult; | |
214 | formatter->format(data, 3, actualResult, errorCode); | |
215 | if (U_FAILURE(errorCode)) { | |
216 | dataerrln( | |
217 | "ListFormatter::createInstance(Locale(\"en\"), errorCode) failed in Test9946: %s", | |
218 | u_errorName(errorCode)); | |
219 | return; | |
220 | } | |
221 | UnicodeString expected("{0}, {1}, and {2}"); | |
222 | if (expected != actualResult) { | |
223 | errln("Expected " + expected + ", got " + actualResult); | |
224 | } | |
225 | } | |
226 | ||
51004dcb A |
227 | void ListFormatterTest::TestEnglishUS() { |
228 | UnicodeString results[4] = { | |
229 | one, | |
230 | one + " and " + two, | |
231 | one + ", " + two + ", and " + three, | |
232 | one + ", " + two + ", " + three + ", and " + four | |
233 | }; | |
234 | ||
3d1f044b | 235 | CheckFourCases("en_US", one, two, three, four, results, "TestEnglishUS()"); |
51004dcb A |
236 | } |
237 | ||
f3c0d7a5 A |
238 | // Tests resource loading and inheritance when region sublocale |
239 | // has only partial data for the listPattern element (overriding | |
240 | // some of the parent data). #12994 | |
241 | void ListFormatterTest::TestEnglishGB() { | |
242 | UnicodeString results[4] = { | |
243 | one, | |
244 | one + " and " + two, | |
245 | one + ", " + two + " and " + three, | |
246 | one + ", " + two + ", " + three + " and " + four | |
247 | }; | |
248 | ||
3d1f044b A |
249 | CheckFourCases("en_GB", one, two, three, four, results, "TestEnglishGB()"); |
250 | } | |
251 | ||
252 | void ListFormatterTest::TestFieldPositionIteratorWontCrash() { | |
253 | IcuTestErrorCode errorCode(*this, "TestFieldPositionIteratorWontCrash()"); | |
254 | LocalPointer<ListFormatter> formatter( | |
255 | ListFormatter::createInstance(Locale("en"), errorCode)); | |
256 | if (U_FAILURE(errorCode)) { | |
257 | dataerrln( | |
258 | "ListFormatter::createInstance(Locale(\"en\"), errorCode) failed in " | |
259 | "TestFieldPositionIteratorWontCrash: %s", | |
260 | u_errorName(errorCode)); | |
261 | return; | |
262 | } | |
263 | UnicodeString data[3] = {"a", "bbb", "cc"}; | |
264 | UnicodeString actualResult; | |
265 | // make sure NULL as FieldPositionIterator won't caused crash. | |
266 | formatter->format(data, 3, actualResult, nullptr, errorCode); | |
267 | if (U_FAILURE(errorCode)) { | |
268 | dataerrln( | |
269 | "ListFormatter::format(data, 3, nullptr, errorCode) " | |
270 | "failed in TestFieldPositionIteratorWontCrash: %s", | |
271 | u_errorName(errorCode)); | |
272 | return; | |
273 | } | |
274 | } | |
275 | ||
276 | void ListFormatterTest::RunTestFieldPositionIteratorWithFormatter( | |
277 | ListFormatter* formatter, | |
278 | UnicodeString data[], int32_t n, int32_t expected[], int32_t tupleCount, | |
279 | UnicodeString& appendTo, const char16_t *expectedFormatted, | |
280 | const char* testName) { | |
281 | IcuTestErrorCode errorCode(*this, testName); | |
282 | FieldPositionIterator iter; | |
283 | formatter->format(data, n, appendTo, &iter, errorCode); | |
284 | if (U_FAILURE(errorCode)) { | |
285 | dataerrln( | |
286 | "ListFormatter::format(data, %d, &iter, errorCode) " | |
287 | "failed in %s: %s", n, testName, u_errorName(errorCode)); | |
288 | return; | |
289 | } | |
290 | if (appendTo != expectedFormatted) { | |
291 | errln(UnicodeString("Expected: |") + expectedFormatted + "|, Actual: |" + appendTo + "|"); | |
292 | } | |
293 | ExpectPositions(iter, expected, tupleCount); | |
294 | } | |
295 | ||
296 | void ListFormatterTest::RunTestFieldPositionIteratorWithNItemsPatternShift( | |
297 | UnicodeString data[], int32_t n, int32_t expected[], int32_t tupleCount, | |
298 | UnicodeString& appendTo, const char16_t *expectedFormatted, | |
299 | const char* testName) { | |
300 | IcuTestErrorCode errorCode(*this, testName); | |
301 | LocalPointer<ListFormatter> formatter( | |
302 | ListFormatter::createInstance(Locale("ur", "IN"), "unit-narrow", errorCode)); | |
303 | if (U_FAILURE(errorCode)) { | |
304 | dataerrln( | |
305 | "ListFormatter::createInstance(Locale(\"ur\", \"IN\"), \"unit-narrow\", errorCode) failed in " | |
306 | "%s: %s", testName, u_errorName(errorCode)); | |
307 | return; | |
308 | } | |
309 | RunTestFieldPositionIteratorWithFormatter( | |
310 | formatter.getAlias(), | |
311 | data, n, expected, tupleCount, appendTo, expectedFormatted, testName); | |
312 | } | |
313 | ||
314 | void ListFormatterTest::RunTestFieldPositionIteratorWithNItems( | |
315 | UnicodeString data[], int32_t n, int32_t expected[], int32_t tupleCount, | |
316 | UnicodeString& appendTo, const char16_t *expectedFormatted, | |
317 | const char* testName) { | |
318 | IcuTestErrorCode errorCode(*this, testName); | |
319 | LocalPointer<ListFormatter> formatter( | |
320 | ListFormatter::createInstance(Locale("en"), errorCode)); | |
321 | if (U_FAILURE(errorCode)) { | |
322 | dataerrln( | |
323 | "ListFormatter::createInstance(Locale(\"en\"), errorCode) failed in " | |
324 | "%s: %s", testName, u_errorName(errorCode)); | |
325 | return; | |
326 | } | |
327 | RunTestFieldPositionIteratorWithFormatter( | |
328 | formatter.getAlias(), | |
329 | data, n, expected, tupleCount, appendTo, expectedFormatted, testName); | |
330 | } | |
331 | ||
332 | void ListFormatterTest::TestFieldPositionIteratorWith3ItemsAndDataBefore() { | |
333 | // 0 1 2 | |
334 | // 0123456789012345678901234567 | |
335 | // "Hello World: a, bbb, and cc" | |
336 | UnicodeString data[3] = {"a", "bbb", "cc"}; | |
337 | int32_t expected[] = { | |
338 | ULISTFMT_ELEMENT_FIELD, 13, 14, | |
339 | ULISTFMT_LITERAL_FIELD, 14, 16, | |
340 | ULISTFMT_ELEMENT_FIELD, 16, 19, | |
341 | ULISTFMT_LITERAL_FIELD, 19, 25, | |
342 | ULISTFMT_ELEMENT_FIELD, 25, 27 | |
343 | }; | |
344 | int32_t tupleCount = sizeof(expected)/(3 * sizeof(*expected)); | |
345 | UnicodeString appendTo(u"Hello World: "); | |
346 | RunTestFieldPositionIteratorWithNItems( | |
347 | data, 3, expected, tupleCount, appendTo, | |
348 | u"Hello World: a, bbb, and cc", | |
349 | "TestFieldPositionIteratorWith3ItemsAndDataBefore"); | |
350 | } | |
351 | ||
352 | void ListFormatterTest::TestFieldPositionIteratorWith3Items() { | |
353 | // 0 1 | |
354 | // 012345678901234 | |
355 | // "a, bbb, and cc" | |
356 | UnicodeString data[3] = {"a", "bbb", "cc"}; | |
357 | int32_t expected[] = { | |
358 | ULISTFMT_ELEMENT_FIELD, 0, 1, | |
359 | ULISTFMT_LITERAL_FIELD, 1, 3, | |
360 | ULISTFMT_ELEMENT_FIELD, 3, 6, | |
361 | ULISTFMT_LITERAL_FIELD, 6, 12, | |
362 | ULISTFMT_ELEMENT_FIELD, 12, 14 | |
363 | }; | |
364 | int32_t tupleCount = sizeof(expected)/(3 * sizeof(*expected)); | |
365 | UnicodeString appendTo; | |
366 | RunTestFieldPositionIteratorWithNItems( | |
367 | data, 3, expected, tupleCount, appendTo, | |
368 | u"a, bbb, and cc", | |
369 | "TestFieldPositionIteratorWith3Items"); | |
370 | } | |
371 | ||
372 | void ListFormatterTest::TestFieldPositionIteratorWith3ItemsPatternShift() { | |
373 | // 0 1 | |
374 | // 012345678901234 | |
375 | // "cc bbb a" | |
376 | UnicodeString data[3] = {"a", "bbb", "cc"}; | |
377 | int32_t expected[] = { | |
378 | ULISTFMT_ELEMENT_FIELD, 7, 8, | |
379 | ULISTFMT_LITERAL_FIELD, 6, 7, | |
380 | ULISTFMT_ELEMENT_FIELD, 3, 6, | |
381 | ULISTFMT_LITERAL_FIELD, 2, 3, | |
382 | ULISTFMT_ELEMENT_FIELD, 0, 2 | |
383 | }; | |
384 | int32_t tupleCount = sizeof(expected)/(3 * sizeof(*expected)); | |
385 | UnicodeString appendTo; | |
386 | RunTestFieldPositionIteratorWithNItemsPatternShift( | |
387 | data, 3, expected, tupleCount, appendTo, | |
388 | u"cc bbb a", | |
389 | "TestFieldPositionIteratorWith3ItemsPatternShift"); | |
390 | } | |
391 | ||
392 | void ListFormatterTest::TestFieldPositionIteratorWith2ItemsAndDataBefore() { | |
393 | // 0 1 | |
394 | // 0123456789012345 | |
395 | // "Foo: bbb and cc" | |
396 | UnicodeString data[2] = {"bbb", "cc"}; | |
397 | int32_t expected[] = { | |
398 | ULISTFMT_ELEMENT_FIELD, 5, 8, | |
399 | ULISTFMT_LITERAL_FIELD, 8, 13, | |
400 | ULISTFMT_ELEMENT_FIELD, 13, 15 | |
401 | }; | |
402 | int32_t tupleCount = sizeof(expected)/(3 * sizeof(*expected)); | |
403 | UnicodeString appendTo("Foo: "); | |
404 | RunTestFieldPositionIteratorWithNItems( | |
405 | data, 2, expected, tupleCount, appendTo, | |
406 | u"Foo: bbb and cc", | |
407 | "TestFieldPositionIteratorWith2ItemsAndDataBefore"); | |
408 | } | |
409 | ||
410 | void ListFormatterTest::TestFieldPositionIteratorWith2Items() { | |
411 | // 0 1 | |
412 | // 01234567890 | |
413 | // "bbb and cc" | |
414 | UnicodeString data[2] = {"bbb", "cc"}; | |
415 | int32_t expected[] = { | |
416 | ULISTFMT_ELEMENT_FIELD, 0, 3, | |
417 | ULISTFMT_LITERAL_FIELD, 3, 8, | |
418 | ULISTFMT_ELEMENT_FIELD, 8, 10 | |
419 | }; | |
420 | int32_t tupleCount = sizeof(expected)/(3 * sizeof(*expected)); | |
421 | UnicodeString appendTo; | |
422 | RunTestFieldPositionIteratorWithNItems( | |
423 | data, 2, expected, tupleCount, appendTo, | |
424 | u"bbb and cc", | |
425 | "TestFieldPositionIteratorWith2Items"); | |
426 | } | |
427 | ||
428 | void ListFormatterTest::TestFieldPositionIteratorWith2ItemsPatternShift() { | |
429 | // 0 1 | |
430 | // 01234567890 | |
431 | // "cc bbb" | |
432 | UnicodeString data[2] = {"bbb", "cc"}; | |
433 | int32_t expected[] = { | |
434 | ULISTFMT_ELEMENT_FIELD, 3, 6, | |
435 | ULISTFMT_LITERAL_FIELD, 2, 3, | |
436 | ULISTFMT_ELEMENT_FIELD, 0, 2 | |
437 | }; | |
438 | int32_t tupleCount = sizeof(expected)/(3 * sizeof(*expected)); | |
439 | UnicodeString appendTo; | |
440 | RunTestFieldPositionIteratorWithNItemsPatternShift( | |
441 | data, 2, expected, tupleCount, appendTo, | |
442 | u"cc bbb", | |
443 | "TestFieldPositionIteratorWith2ItemsPatternShift"); | |
444 | } | |
445 | ||
446 | void ListFormatterTest::TestFieldPositionIteratorWith1ItemAndDataBefore() { | |
447 | // 012345678 | |
448 | // "Hello cc" | |
449 | UnicodeString data[1] = {"cc"}; | |
450 | int32_t expected[] = { | |
451 | ULISTFMT_ELEMENT_FIELD, 6, 8 | |
452 | }; | |
453 | int32_t tupleCount = sizeof(expected)/(3 * sizeof(*expected)); | |
454 | UnicodeString appendTo("Hello "); | |
455 | RunTestFieldPositionIteratorWithNItems( | |
456 | data, 1, expected, tupleCount, appendTo, | |
457 | u"Hello cc", | |
458 | "TestFieldPositionIteratorWith1ItemAndDataBefore"); | |
459 | } | |
460 | ||
461 | void ListFormatterTest::TestFieldPositionIteratorWith1Item() { | |
462 | // 012 | |
463 | // "cc" | |
464 | UnicodeString data[1] = {"cc"}; | |
465 | int32_t expected[] = { | |
466 | ULISTFMT_ELEMENT_FIELD, 0, 2 | |
467 | }; | |
468 | int32_t tupleCount = sizeof(expected)/(3 * sizeof(*expected)); | |
469 | UnicodeString appendTo; | |
470 | RunTestFieldPositionIteratorWithNItems( | |
471 | data, 1, expected, tupleCount, appendTo, | |
472 | u"cc", | |
473 | "TestFieldPositionIteratorWith1Item"); | |
f3c0d7a5 A |
474 | } |
475 | ||
476 | // Tests resource loading and inheritance when region sublocale | |
477 | // has only partial data for the listPattern element (overriding | |
478 | // some of the parent data). #12994 | |
479 | void ListFormatterTest::TestNynorsk() { | |
480 | UnicodeString results[4] = { | |
481 | one, | |
482 | one + " og " + two, | |
483 | one + ", " + two + " og " + three, | |
484 | one + ", " + two + ", " + three + " og " + four | |
485 | }; | |
486 | ||
3d1f044b | 487 | CheckFourCases("nn", one, two, three, four, results, "TestNynorsk()"); |
f3c0d7a5 A |
488 | } |
489 | ||
490 | // Tests resource loading and inheritance when region sublocale | |
491 | // has only partial data for the listPattern element (overriding | |
492 | // some of the parent data). #12994 | |
493 | void ListFormatterTest::TestChineseTradHK() { | |
494 | UnicodeString and_string = UnicodeString("\\u53CA", -1, US_INV).unescape(); | |
495 | UnicodeString comma_string = UnicodeString("\\u3001", -1, US_INV).unescape(); | |
496 | UnicodeString results[4] = { | |
497 | one, | |
498 | one + and_string + two, | |
499 | one + comma_string + two + and_string + three, | |
500 | one + comma_string + two + comma_string + three + and_string + four | |
501 | }; | |
502 | ||
3d1f044b | 503 | CheckFourCases("zh_Hant_HK", one, two, three, four, results, "TestChineseTradHK()"); |
f3c0d7a5 A |
504 | } |
505 | ||
51004dcb A |
506 | // Formatting in Russian. |
507 | // "\\u0438" is used before the last element, and all elements up to (but not including) the penultimate are followed by a comma. | |
508 | void ListFormatterTest::TestRussian() { | |
509 | UnicodeString and_string = UnicodeString(" \\u0438 ", -1, US_INV).unescape(); | |
510 | UnicodeString results[4] = { | |
511 | one, | |
512 | one + and_string + two, | |
513 | one + ", " + two + and_string + three, | |
514 | one + ", " + two + ", " + three + and_string + four | |
515 | }; | |
516 | ||
3d1f044b | 517 | CheckFourCases("ru", one, two, three, four, results, "TestRussian()"); |
51004dcb A |
518 | } |
519 | ||
520 | // Formatting in Malayalam. | |
521 | // For two elements, "\\u0d15\\u0d42\\u0d1f\\u0d3e\\u0d24\\u0d46" is inserted in between. | |
522 | // For more than two elements, comma is inserted between all elements up to (and including) the penultimate, | |
523 | // and the word \\u0d0e\\u0d28\\u0d4d\\u0d28\\u0d3f\\u0d35 is inserted in the end. | |
524 | void ListFormatterTest::TestMalayalam() { | |
525 | UnicodeString pair_string = UnicodeString(" \\u0d15\\u0d42\\u0d1f\\u0d3e\\u0d24\\u0d46 ", -1, US_INV).unescape(); | |
526 | UnicodeString total_string = UnicodeString(" \\u0d0e\\u0d28\\u0d4d\\u0d28\\u0d3f\\u0d35", -1, US_INV).unescape(); | |
527 | UnicodeString results[4] = { | |
528 | one, | |
529 | one + pair_string + two, | |
530 | one + ", " + two + ", " + three + total_string, | |
531 | one + ", " + two + ", " + three + ", " + four + total_string | |
532 | }; | |
533 | ||
3d1f044b | 534 | CheckFourCases("ml", one, two, three, four, results, "TestMalayalam()"); |
51004dcb A |
535 | } |
536 | ||
537 | // Formatting in Zulu. | |
538 | // "and" is used before the last element, and all elements up to (and including) the penultimate are followed by a comma. | |
539 | void ListFormatterTest::TestZulu() { | |
540 | UnicodeString results[4] = { | |
541 | one, | |
f3c0d7a5 | 542 | one + " ne-" + two, |
b331163b A |
543 | one + ", " + two + ", ne-" + three, |
544 | one + ", " + two + ", " + three + ", ne-" + four | |
51004dcb A |
545 | }; |
546 | ||
3d1f044b | 547 | CheckFourCases("zu", one, two, three, four, results, "TestZulu()"); |
51004dcb A |
548 | } |
549 | ||
550 | void ListFormatterTest::TestOutOfOrderPatterns() { | |
551 | UnicodeString results[4] = { | |
552 | one, | |
553 | two + " after " + one, | |
554 | three + " in the last after " + two + " after the first " + one, | |
555 | four + " in the last after " + three + " after " + two + " after the first " + one | |
556 | }; | |
557 | ||
3d1f044b | 558 | IcuTestErrorCode errorCode(*this, "TestOutOfOrderPatterns()"); |
340931cb | 559 | Locale locale("en"); |
51004dcb | 560 | ListFormatData data("{1} after {0}", "{1} after the first {0}", |
340931cb | 561 | "{1} after {0}", "{1} in the last after {0}", locale); |
2ca993e8 | 562 | ListFormatter formatter(data, errorCode); |
51004dcb A |
563 | |
564 | UnicodeString input1[] = {one}; | |
3d1f044b | 565 | CheckFormatting(&formatter, input1, 1, results[0], "TestOutOfOrderPatterns()"); |
51004dcb A |
566 | |
567 | UnicodeString input2[] = {one, two}; | |
3d1f044b | 568 | CheckFormatting(&formatter, input2, 2, results[1], "TestOutOfOrderPatterns()"); |
51004dcb A |
569 | |
570 | UnicodeString input3[] = {one, two, three}; | |
3d1f044b | 571 | CheckFormatting(&formatter, input3, 3, results[2], "TestOutOfOrderPatterns()"); |
51004dcb A |
572 | |
573 | UnicodeString input4[] = {one, two, three, four}; | |
3d1f044b A |
574 | CheckFormatting(&formatter, input4, 4, results[3], "TestOutOfOrderPatterns()"); |
575 | } | |
576 | ||
577 | void ListFormatterTest::TestFormattedValue() { | |
578 | IcuTestErrorCode status(*this, "TestFormattedValue"); | |
579 | LocalPointer<ListFormatter> fmt(ListFormatter::createInstance("en", status)); | |
580 | if (status.errIfFailureAndReset()) { return; } | |
581 | ||
582 | { | |
583 | const char16_t* message = u"Field position test 1"; | |
584 | const char16_t* expectedString = u"hello, wonderful, and world"; | |
585 | const UnicodeString inputs[] = { | |
586 | u"hello", | |
587 | u"wonderful", | |
588 | u"world" | |
589 | }; | |
590 | FormattedList result = fmt->formatStringsToValue(inputs, UPRV_LENGTHOF(inputs), status); | |
591 | static const UFieldPositionWithCategory expectedFieldPositions[] = { | |
592 | // field, begin index, end index | |
593 | {UFIELD_CATEGORY_LIST_SPAN, 0, 0, 5}, | |
594 | {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 0, 5}, | |
595 | {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 5, 7}, | |
596 | {UFIELD_CATEGORY_LIST_SPAN, 1, 7, 16}, | |
597 | {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 7, 16}, | |
598 | {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 16, 22}, | |
599 | {UFIELD_CATEGORY_LIST_SPAN, 2, 22, 27}, | |
600 | {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 22, 27}}; | |
601 | checkMixedFormattedValue( | |
602 | message, | |
603 | result, | |
604 | expectedString, | |
605 | expectedFieldPositions, | |
606 | UPRV_LENGTHOF(expectedFieldPositions)); | |
607 | } | |
608 | } | |
609 | ||
610 | void ListFormatterTest::DoTheRealListStyleTesting(Locale locale, | |
611 | UnicodeString items[], int itemCount, | |
612 | const char* style, const char* expected, IcuTestErrorCode status) { | |
613 | ||
614 | LocalPointer<ListFormatter> formatter( | |
615 | ListFormatter::createInstance(locale, style, status)); | |
616 | ||
617 | UnicodeString actualResult; | |
618 | formatter->format(items, itemCount, actualResult, status); | |
619 | assertEquals(style, UnicodeString(expected), actualResult); | |
620 | } | |
621 | ||
622 | void ListFormatterTest::TestDifferentStyles() { | |
623 | Locale locale("fr"); | |
624 | UnicodeString input[4] = { u"rouge", u"jaune", u"bleu", u"vert" }; | |
625 | IcuTestErrorCode status(*this, "TestDifferentStyles()"); | |
626 | ||
627 | DoTheRealListStyleTesting(locale, input, 4, "standard", "rouge, jaune, bleu et vert", status); | |
628 | DoTheRealListStyleTesting(locale, input, 4, "or", "rouge, jaune, bleu ou vert", status); | |
629 | DoTheRealListStyleTesting(locale, input, 4, "unit", "rouge, jaune, bleu et vert", status); | |
630 | DoTheRealListStyleTesting(locale, input, 4, "unit-narrow", "rouge jaune bleu vert", status); | |
631 | DoTheRealListStyleTesting(locale, input, 4, "unit-short", "rouge, jaune, bleu et vert", status); | |
632 | } | |
633 | ||
634 | void ListFormatterTest::TestBadStylesFail() { | |
635 | Locale locale("fr"); | |
636 | const char * badStyles[4] = { "", "duration", "duration-short", "something-clearly-wrong" }; | |
637 | IcuTestErrorCode status(*this, "TestBadStylesFail()"); | |
638 | ||
639 | for (int i = 0; i < 4; ++i) { | |
640 | LocalPointer<ListFormatter> formatter(ListFormatter::createInstance(locale, badStyles[i], status)); | |
641 | if (!status.expectErrorAndReset(U_MISSING_RESOURCE_ERROR, "style \"%s\"", badStyles[i])) { | |
642 | // Do nothing, expectErrorAndReset already reports the error | |
643 | } | |
644 | } | |
51004dcb A |
645 | } |
646 | ||
340931cb A |
647 | void ListFormatterTest::TestCreateStyled() { |
648 | IcuTestErrorCode status(*this, "TestCreateStyled"); | |
649 | // Locale en has interesting data | |
650 | struct TestCase { | |
651 | const char* locale; | |
652 | UListFormatterType type; | |
653 | UListFormatterWidth width; | |
654 | const char16_t* expected3; | |
655 | const char16_t* expected2; | |
656 | const char16_t* expected1; | |
657 | } cases[] = { | |
658 | { "pt", ULISTFMT_TYPE_AND, ULISTFMT_WIDTH_WIDE, u"A, B e C", u"A e B", u"A" }, | |
659 | { "pt", ULISTFMT_TYPE_AND, ULISTFMT_WIDTH_SHORT, u"A, B e C", u"A e B", u"A" }, | |
660 | { "pt", ULISTFMT_TYPE_AND, ULISTFMT_WIDTH_NARROW, u"A, B, C", u"A, B", u"A" }, | |
661 | { "pt", ULISTFMT_TYPE_OR, ULISTFMT_WIDTH_WIDE, u"A, B ou C", u"A ou B", u"A" }, | |
662 | { "pt", ULISTFMT_TYPE_OR, ULISTFMT_WIDTH_SHORT, u"A, B ou C", u"A ou B", u"A" }, | |
663 | { "pt", ULISTFMT_TYPE_OR, ULISTFMT_WIDTH_NARROW, u"A, B ou C", u"A ou B", u"A" }, | |
664 | { "pt", ULISTFMT_TYPE_UNITS, ULISTFMT_WIDTH_WIDE, u"A, B e C", u"A e B", u"A" }, | |
665 | { "pt", ULISTFMT_TYPE_UNITS, ULISTFMT_WIDTH_SHORT, u"A, B e C", u"A e B", u"A" }, | |
666 | { "pt", ULISTFMT_TYPE_UNITS, ULISTFMT_WIDTH_NARROW, u"A B C", u"A B", u"A" }, | |
667 | { "en", ULISTFMT_TYPE_AND, ULISTFMT_WIDTH_WIDE, u"A, B, and C", u"A and B", u"A" }, | |
668 | { "en", ULISTFMT_TYPE_AND, ULISTFMT_WIDTH_SHORT, u"A, B, & C", u"A & B", u"A" }, | |
669 | { "en", ULISTFMT_TYPE_AND, ULISTFMT_WIDTH_NARROW, u"A, B, C", u"A, B", u"A" }, | |
670 | { "en", ULISTFMT_TYPE_OR, ULISTFMT_WIDTH_WIDE, u"A, B, or C", u"A or B", u"A" }, | |
671 | { "en", ULISTFMT_TYPE_OR, ULISTFMT_WIDTH_SHORT, u"A, B, or C", u"A or B", u"A" }, | |
672 | { "en", ULISTFMT_TYPE_OR, ULISTFMT_WIDTH_NARROW, u"A, B, or C", u"A or B", u"A" }, | |
673 | { "en", ULISTFMT_TYPE_UNITS, ULISTFMT_WIDTH_WIDE, u"A, B, C", u"A, B", u"A" }, | |
674 | { "en", ULISTFMT_TYPE_UNITS, ULISTFMT_WIDTH_SHORT, u"A, B, C", u"A, B", u"A" }, | |
675 | { "en", ULISTFMT_TYPE_UNITS, ULISTFMT_WIDTH_NARROW, u"A B C", u"A B", u"A" }, | |
676 | }; | |
677 | for (auto cas : cases) { | |
678 | LocalPointer<ListFormatter> fmt( | |
679 | ListFormatter::createInstance(cas.locale, cas.type, cas.width, status), | |
680 | status); | |
681 | if (status.errIfFailureAndReset()) { | |
682 | continue; | |
683 | } | |
684 | UnicodeString message = UnicodeString(u"TestCreateStyled loc=") | |
685 | + cas.locale + u" type=" | |
686 | + Int64ToUnicodeString(cas.type) + u" width=" | |
687 | + Int64ToUnicodeString(cas.width); | |
688 | const UnicodeString inputs3[] = { | |
689 | u"A", | |
690 | u"B", | |
691 | u"C" | |
692 | }; | |
693 | FormattedList result = fmt->formatStringsToValue(inputs3, UPRV_LENGTHOF(inputs3), status); | |
694 | assertEquals(message, cas.expected3, result.toTempString(status)); | |
695 | const UnicodeString inputs2[] = { | |
696 | u"A", | |
697 | u"B" | |
698 | }; | |
699 | result = fmt->formatStringsToValue(inputs2, UPRV_LENGTHOF(inputs2), status); | |
700 | assertEquals(message, cas.expected2, result.toTempString(status)); | |
701 | const UnicodeString inputs1[] = { | |
702 | u"A" | |
703 | }; | |
704 | result = fmt->formatStringsToValue(inputs1, UPRV_LENGTHOF(inputs1), status); | |
705 | assertEquals(message, cas.expected1, result.toTempString(status)); | |
706 | } | |
707 | } | |
708 | ||
709 | void ListFormatterTest::TestContextual() { | |
710 | IcuTestErrorCode status(*this, "TestContextual"); | |
711 | std::vector<std::string> es = { "es", "es_419" , "es_PY", "es_DO" }; | |
712 | std::vector<std::string> he = { "he", "he_IL", "iw", "iw_IL" }; | |
713 | std::vector<std::string> th = { "th", "th_TH" }; | |
714 | UListFormatterWidth widths [] = { | |
715 | ULISTFMT_WIDTH_WIDE, ULISTFMT_WIDTH_SHORT, ULISTFMT_WIDTH_NARROW | |
716 | }; | |
717 | struct TestCase { | |
718 | std::vector<std::string> locales; | |
719 | UListFormatterType type; | |
720 | const char16_t* expected; | |
721 | const char16_t* data1; | |
722 | const char16_t* data2; | |
723 | const char16_t* data3; | |
724 | } cases[] = { | |
725 | { es, ULISTFMT_TYPE_AND, u"fascinante e increíblemente", | |
726 | u"fascinante", u"increíblemente", nullptr }, | |
727 | { es, ULISTFMT_TYPE_AND, u"Comunicaciones Industriales e IIoT", | |
728 | u"Comunicaciones Industriales", u"IIoT", nullptr }, | |
729 | { es, ULISTFMT_TYPE_AND, u"España e Italia", u"España", u"Italia", nullptr }, | |
730 | { es, ULISTFMT_TYPE_AND, u"hijas intrépidas e hijos solidarios", | |
731 | u"hijas intrépidas", u"hijos solidarios", nullptr }, | |
732 | { es, ULISTFMT_TYPE_AND, u"a un hombre e hirieron a otro", | |
733 | u"a un hombre", u"hirieron a otro", nullptr }, | |
734 | { es, ULISTFMT_TYPE_AND, u"hija e hijo", u"hija", u"hijo", nullptr }, | |
735 | { es, ULISTFMT_TYPE_AND, u"esposa, hija e hijo", u"esposa", u"hija", u"hijo" }, | |
736 | // For 'y' exception | |
737 | { es, ULISTFMT_TYPE_AND, u"oro y hierro", u"oro", u"hierro", nullptr }, | |
738 | { es, ULISTFMT_TYPE_AND, u"agua y hielo", u"agua", u"hielo", nullptr }, | |
739 | { es, ULISTFMT_TYPE_AND, u"colágeno y hialurónico", u"colágeno", u"hialurónico", nullptr }, | |
740 | ||
741 | { es, ULISTFMT_TYPE_OR, u"desierto u oasis", u"desierto", u"oasis", nullptr }, | |
742 | { es, ULISTFMT_TYPE_OR, u"oasis, desierto u océano", u"oasis", u"desierto", u"océano" }, | |
743 | { es, ULISTFMT_TYPE_OR, u"7 u 8", u"7", u"8", nullptr }, | |
744 | { es, ULISTFMT_TYPE_OR, u"7 u 80", u"7", u"80", nullptr }, | |
745 | { es, ULISTFMT_TYPE_OR, u"7 u 800", u"7", u"800", nullptr }, | |
746 | { es, ULISTFMT_TYPE_OR, u"6, 7 u 8", u"6", u"7", u"8" }, | |
747 | { es, ULISTFMT_TYPE_OR, u"10 u 11", u"10", u"11", nullptr }, | |
748 | { es, ULISTFMT_TYPE_OR, u"10 o 111", u"10", u"111", nullptr }, | |
749 | { es, ULISTFMT_TYPE_OR, u"10 o 11.2", u"10", u"11.2", nullptr }, | |
750 | { es, ULISTFMT_TYPE_OR, u"9, 10 u 11", u"9", u"10", u"11" }, | |
751 | ||
752 | { he, ULISTFMT_TYPE_AND, u"a, b ו-c", u"a", u"b", u"c" }, | |
753 | { he, ULISTFMT_TYPE_AND, u"a ו-b", u"a", u"b", nullptr }, | |
754 | { he, ULISTFMT_TYPE_AND, u"1, 2 ו-3", u"1", u"2", u"3" }, | |
755 | { he, ULISTFMT_TYPE_AND, u"1 ו-2", u"1", u"2", nullptr }, | |
756 | { he, ULISTFMT_TYPE_AND, u"אהבה ומקווה", u"אהבה", u"מקווה", nullptr }, | |
757 | { he, ULISTFMT_TYPE_AND, u"אהבה, מקווה ואמונה", u"אהבה", u"מקווה", u"אמונה" }, | |
758 | ||
759 | // rdar://64483589 | |
760 | { th, ULISTFMT_TYPE_AND, u"ข้อความธรรมดาและ 1 ภาพ", u"ข้อความธรรมดา", u"1 ภาพ", nullptr }, | |
761 | { th, ULISTFMT_TYPE_AND, u"ข้อความธรรมดาและข้อความธรรมดา", u"ข้อความธรรมดา", u"ข้อความธรรมดา", nullptr }, | |
762 | { th, ULISTFMT_TYPE_AND, u"0 และ 1 ภาพ", u"0", u"1 ภาพ", nullptr }, | |
763 | { th, ULISTFMT_TYPE_AND, u"0 และข้อความธรรมดา", u"0", u"ข้อความธรรมดา", nullptr }, | |
764 | { th, ULISTFMT_TYPE_AND, u"ข้อความธรรมดา ข้อความธรรมดา และข้อความธรรมดา", u"ข้อความธรรมดา", u"ข้อความธรรมดา", u"ข้อความธรรมดา" }, | |
765 | { th, ULISTFMT_TYPE_AND, u"ข้อความธรรมดา ข้อความธรรมดา และ 1 ภาพ", u"ข้อความธรรมดา", u"ข้อความธรรมดา", u"1 ภาพ" }, | |
766 | { th, ULISTFMT_TYPE_OR, u"ข้อความธรรมดา หรือ 1 ภาพ", u"ข้อความธรรมดา", u"1 ภาพ", nullptr }, | |
767 | { th, ULISTFMT_TYPE_OR, u"ข้อความธรรมดา หรือ ข้อความธรรมดา", u"ข้อความธรรมดา", u"ข้อความธรรมดา", nullptr }, | |
768 | { th, ULISTFMT_TYPE_OR, u"ข้อความธรรมดา, ข้อความธรรมดา หรือ 1 ภาพ", u"ข้อความธรรมดา", u"ข้อความธรรมดา", u"1 ภาพ" }, | |
769 | }; | |
770 | for (auto width : widths) { | |
771 | for (auto cas : cases) { | |
772 | for (auto locale : cas.locales) { | |
773 | if ((locale == "th" || locale == "th_TH") && cas.type == ULISTFMT_TYPE_OR && (width == ULISTFMT_WIDTH_SHORT || width == ULISTFMT_WIDTH_NARROW)) { | |
774 | // this test was written to assume all the widths product the same result, but that isn't | |
775 | // true of the Thai "or" formats, so we skip the short and narrow Thai "or" formats (which | |
776 | // work the same way as the "and" formats) | |
777 | continue; | |
778 | } | |
779 | ||
780 | LocalPointer<ListFormatter> fmt( | |
781 | ListFormatter::createInstance(locale.c_str(), cas.type, width, status), | |
782 | status); | |
783 | if (status.errIfFailureAndReset()) { | |
784 | continue; | |
785 | } | |
786 | UnicodeString message = UnicodeString(u"TestContextual loc=") | |
787 | + locale.c_str() + u" type=" | |
788 | + Int64ToUnicodeString(cas.type) + u" width=" | |
789 | + Int64ToUnicodeString(width); | |
790 | if (cas.data3 == nullptr) { | |
791 | const UnicodeString inputs2[] = { cas.data1, cas.data2 }; | |
792 | FormattedList result = fmt->formatStringsToValue(inputs2, UPRV_LENGTHOF(inputs2), status); | |
793 | assertEquals(message, cas.expected, result.toTempString(status)); | |
794 | } else { | |
795 | const UnicodeString inputs3[] = { cas.data1, cas.data2, cas.data3 }; | |
796 | FormattedList result = fmt->formatStringsToValue(inputs3, UPRV_LENGTHOF(inputs3), status); | |
797 | assertEquals(message, cas.expected, result.toTempString(status)); | |
798 | } | |
799 | } | |
800 | } | |
51004dcb A |
801 | } |
802 | } | |
3d1f044b A |
803 | |
804 | #endif /* #if !UCONFIG_NO_FORMATTING */ |