1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /********************************************************************
4 * Copyright (c) 2015, International Business Machines Corporation
5 * and others. All Rights Reserved.
6 ********************************************************************/
7 /* C API TEST for UListFormatter */
8
9 #include "unicode/utypes.h"
10
11 #if !UCONFIG_NO_FORMATTING
12
13 #include "unicode/ustring.h"
14 #include "unicode/ulistformatter.h"
15 #include "cintltst.h"
16 #include "cmemory.h"
17 #include "cstring.h"
18 #include "cformtst.h"
19
20 static void TestUListFmt(void);
21 static void TestUListFmtToValue(void);
22 static void TestUListOpenStyled(void);
23 static void TestUList21871_A(void);
24 static void TestUList21871_B(void);
25
26 void addUListFmtTest(TestNode** root);
27
28 #define TESTCASE(x) addTest(root, &x, "tsformat/ulistfmttest/" #x)
29
addUListFmtTest(TestNode ** root)30 void addUListFmtTest(TestNode** root)
31 {
32 TESTCASE(TestUListFmt);
33 TESTCASE(TestUListFmtToValue);
34 TESTCASE(TestUListOpenStyled);
35 TESTCASE(TestUList21871_A);
36 TESTCASE(TestUList21871_B);
37 }
38
39 static const UChar str0[] = { 0x41,0 }; /* "A" */
40 static const UChar str1[] = { 0x42,0x62,0 }; /* "Bb" */
41 static const UChar str2[] = { 0x43,0x63,0x63,0 }; /* "Ccc" */
42 static const UChar str3[] = { 0x44,0x64,0x64,0x64,0 }; /* "Dddd" */
43 static const UChar str4[] = { 0x45,0x65,0x65,0x65,0x65,0 }; /* "Eeeee" */
44 static const UChar* strings[] = { str0, str1, str2, str3, str4 };
45 static const int32_t stringLengths[] = { 1, 2, 3, 4, 5 };
46 static const int32_t stringLengthsNeg[] = { -1, -1, -1, -1, -1 };
47
48 typedef struct {
49 const char * locale;
50 int32_t stringCount;
51 const char *expectedResult; /* invariant chars + escaped Unicode */
52 } ListFmtTestEntry;
53
54 static ListFmtTestEntry listFmtTestEntries[] = {
55 /* locale stringCount expectedResult */
56 { "en" , 5, "A, Bb, Ccc, Dddd, and Eeeee" },
57 { "en" , 2, "A and Bb" },
58 { "de" , 5, "A, Bb, Ccc, Dddd und Eeeee" },
59 { "de" , 2, "A und Bb" },
60 { "ja" , 5, "A\\u3001Bb\\u3001Ccc\\u3001Dddd\\u3001Eeeee" },
61 { "ja" , 2, "A\\u3001Bb" },
62 { "zh" , 5, "A\\u3001Bb\\u3001Ccc\\u3001Dddd\\u548CEeeee" },
63 { "zh" , 2, "A\\u548CBb" },
64 { NULL , 0, NULL } /* terminator */
65 };
66
67 enum {
68 kUBufMax = 128,
69 kBBufMax = 256
70 };
71
TestUListFmt()72 static void TestUListFmt() {
73 const ListFmtTestEntry * lftep;
74 for (lftep = listFmtTestEntries; lftep->locale != NULL ; lftep++ ) {
75 UErrorCode status = U_ZERO_ERROR;
76 UListFormatter *listfmt = ulistfmt_open(lftep->locale, &status);
77 if ( U_FAILURE(status) ) {
78 log_data_err("ERROR: ulistfmt_open fails for locale %s, status %s\n", lftep->locale, u_errorName(status));
79 } else {
80 UChar ubufActual[kUBufMax];
81 int32_t ulenActual = ulistfmt_format(listfmt, strings, stringLengths, lftep->stringCount, ubufActual, kUBufMax, &status);
82 if ( U_FAILURE(status) ) {
83 log_err("ERROR: ulistfmt_format fails for locale %s count %d (real lengths), status %s\n", lftep->locale, lftep->stringCount, u_errorName(status));
84 } else {
85 UChar ubufExpected[kUBufMax];
86 int32_t ulenExpected = u_unescape(lftep->expectedResult, ubufExpected, kUBufMax);
87 if (ulenActual != ulenExpected || u_strncmp(ubufActual, ubufExpected, ulenExpected) != 0) {
88 log_err("ERROR: ulistfmt_format for locale %s count %d (real lengths), actual \"%s\" != expected \"%s\"\n", lftep->locale,
89 lftep->stringCount, aescstrdup(ubufActual, ulenActual), aescstrdup(ubufExpected, ulenExpected));
90 }
91 }
92 /* try again with all lengths -1 */
93 status = U_ZERO_ERROR;
94 ulenActual = ulistfmt_format(listfmt, strings, stringLengthsNeg, lftep->stringCount, ubufActual, kUBufMax, &status);
95 if ( U_FAILURE(status) ) {
96 log_err("ERROR: ulistfmt_format fails for locale %s count %d (-1 lengths), status %s\n", lftep->locale, lftep->stringCount, u_errorName(status));
97 } else {
98 UChar ubufExpected[kUBufMax];
99 int32_t ulenExpected = u_unescape(lftep->expectedResult, ubufExpected, kUBufMax);
100 if (ulenActual != ulenExpected || u_strncmp(ubufActual, ubufExpected, ulenExpected) != 0) {
101 log_err("ERROR: ulistfmt_format for locale %s count %d (-1 lengths), actual \"%s\" != expected \"%s\"\n", lftep->locale,
102 lftep->stringCount, aescstrdup(ubufActual, ulenActual), aescstrdup(ubufExpected, ulenExpected));
103 }
104 }
105 /* try again with NULL lengths */
106 status = U_ZERO_ERROR;
107 ulenActual = ulistfmt_format(listfmt, strings, NULL, lftep->stringCount, ubufActual, kUBufMax, &status);
108 if ( U_FAILURE(status) ) {
109 log_err("ERROR: ulistfmt_format fails for locale %s count %d (NULL lengths), status %s\n", lftep->locale, lftep->stringCount, u_errorName(status));
110 } else {
111 UChar ubufExpected[kUBufMax];
112 int32_t ulenExpected = u_unescape(lftep->expectedResult, ubufExpected, kUBufMax);
113 if (ulenActual != ulenExpected || u_strncmp(ubufActual, ubufExpected, ulenExpected) != 0) {
114 log_err("ERROR: ulistfmt_format for locale %s count %d (NULL lengths), actual \"%s\" != expected \"%s\"\n", lftep->locale,
115 lftep->stringCount, aescstrdup(ubufActual, ulenActual), aescstrdup(ubufExpected, ulenExpected));
116 }
117 }
118
119 /* try calls that should return error */
120 status = U_ZERO_ERROR;
121 ulenActual = ulistfmt_format(listfmt, NULL, NULL, lftep->stringCount, ubufActual, kUBufMax, &status);
122 if (status != U_ILLEGAL_ARGUMENT_ERROR || ulenActual > 0) {
123 log_err("ERROR: ulistfmt_format for locale %s count %d with NULL strings, expected U_ILLEGAL_ARGUMENT_ERROR, got %s, result %d\n", lftep->locale,
124 lftep->stringCount, u_errorName(status), ulenActual);
125 }
126 status = U_ZERO_ERROR;
127 ulenActual = ulistfmt_format(listfmt, strings, NULL, lftep->stringCount, NULL, kUBufMax, &status);
128 if (status != U_ILLEGAL_ARGUMENT_ERROR || ulenActual > 0) {
129 log_err("ERROR: ulistfmt_format for locale %s count %d with NULL result, expected U_ILLEGAL_ARGUMENT_ERROR, got %s, result %d\n", lftep->locale,
130 lftep->stringCount, u_errorName(status), ulenActual);
131 }
132
133 ulistfmt_close(listfmt);
134 }
135 }
136 }
137
TestUListFmtToValue()138 static void TestUListFmtToValue() {
139 UErrorCode ec = U_ZERO_ERROR;
140 UListFormatter* fmt = ulistfmt_open("en", &ec);
141 UFormattedList* fl = ulistfmt_openResult(&ec);
142 assertSuccess("Opening", &ec);
143
144 {
145 const char* message = "Field position test 1";
146 const UChar* expectedString = u"hello, wonderful, and world";
147 const UChar* inputs[] = {
148 u"hello",
149 u"wonderful",
150 u"world"
151 };
152 ulistfmt_formatStringsToResult(fmt, inputs, NULL, UPRV_LENGTHOF(inputs), fl, &ec);
153 assertSuccess("Formatting", &ec);
154 static const UFieldPositionWithCategory expectedFieldPositions[] = {
155 // field, begin index, end index
156 {UFIELD_CATEGORY_LIST_SPAN, 0, 0, 5},
157 {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 0, 5},
158 {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 5, 7},
159 {UFIELD_CATEGORY_LIST_SPAN, 1, 7, 16},
160 {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 7, 16},
161 {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 16, 22},
162 {UFIELD_CATEGORY_LIST_SPAN, 2, 22, 27},
163 {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 22, 27}};
164 checkMixedFormattedValue(
165 message,
166 ulistfmt_resultAsValue(fl, &ec),
167 expectedString,
168 expectedFieldPositions,
169 UPRV_LENGTHOF(expectedFieldPositions));
170 }
171 {
172 const char* message = "Field position test 1";
173 const UChar* expectedString = u"A, B, C, D, E, F, and G";
174 const UChar* inputs[] = {
175 u"A",
176 u"B",
177 u"C",
178 u"D",
179 u"E",
180 u"F",
181 u"G"
182 };
183 ulistfmt_formatStringsToResult(fmt, inputs, NULL, UPRV_LENGTHOF(inputs), fl, &ec);
184 assertSuccess("Formatting", &ec);
185 static const UFieldPositionWithCategory expectedFieldPositions[] = {
186 // field, begin index, end index
187 {UFIELD_CATEGORY_LIST_SPAN, 0, 0, 1},
188 {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 0, 1},
189 {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 1, 3},
190 {UFIELD_CATEGORY_LIST_SPAN, 1, 3, 4},
191 {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 3, 4},
192 {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 4, 6},
193 {UFIELD_CATEGORY_LIST_SPAN, 2, 6, 7},
194 {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 6, 7},
195 {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 7, 9},
196 {UFIELD_CATEGORY_LIST_SPAN, 3, 9, 10},
197 {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 9, 10},
198 {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 10, 12},
199 {UFIELD_CATEGORY_LIST_SPAN, 4, 12, 13},
200 {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 12, 13},
201 {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 13, 15},
202 {UFIELD_CATEGORY_LIST_SPAN, 5, 15, 16},
203 {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 15, 16},
204 {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 16, 22},
205 {UFIELD_CATEGORY_LIST_SPAN, 6, 22, 23},
206 {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 22, 23}};
207 checkMixedFormattedValue(
208 message,
209 ulistfmt_resultAsValue(fl, &ec),
210 expectedString,
211 expectedFieldPositions,
212 UPRV_LENGTHOF(expectedFieldPositions));
213 }
214
215 ulistfmt_close(fmt);
216 ulistfmt_closeResult(fl);
217 }
218
TestUListOpenStyled()219 static void TestUListOpenStyled() {
220 UErrorCode ec = U_ZERO_ERROR;
221 UListFormatter* fmt = ulistfmt_openForType("en", ULISTFMT_TYPE_OR, ULISTFMT_WIDTH_SHORT, &ec);
222 UFormattedList* fl = ulistfmt_openResult(&ec);
223 assertSuccess("Opening", &ec);
224
225 {
226 const char* message = "openStyled test 1";
227 const UChar* expectedString = u"A, B, or C";
228 const UChar* inputs[] = {
229 u"A",
230 u"B",
231 u"C",
232 };
233 ulistfmt_formatStringsToResult(fmt, inputs, NULL, UPRV_LENGTHOF(inputs), fl, &ec);
234 assertSuccess("Formatting", &ec);
235 static const UFieldPositionWithCategory expectedFieldPositions[] = {
236 // field, begin index, end index
237 {UFIELD_CATEGORY_LIST_SPAN, 0, 0, 1},
238 {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 0, 1},
239 {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 1, 3},
240 {UFIELD_CATEGORY_LIST_SPAN, 1, 3, 4},
241 {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 3, 4},
242 {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 4, 9},
243 {UFIELD_CATEGORY_LIST_SPAN, 2, 9, 10},
244 {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 9, 10}};
245 checkMixedFormattedValue(
246 message,
247 ulistfmt_resultAsValue(fl, &ec),
248 expectedString,
249 expectedFieldPositions,
250 UPRV_LENGTHOF(expectedFieldPositions));
251 }
252
253 ulistfmt_close(fmt);
254 ulistfmt_closeResult(fl);
255 }
256
257 #include <stdio.h>
258
TestUList21871_A()259 static void TestUList21871_A() {
260 UErrorCode status = U_ZERO_ERROR;
261 UListFormatter *fmt = ulistfmt_openForType("en", ULISTFMT_TYPE_AND, ULISTFMT_WIDTH_WIDE, &status);
262 assertSuccess("ulistfmt_openForType", &status);
263
264 const UChar *strs[] = {u"A", u""};
265 const int32_t lens[] = {1, 0};
266
267 UFormattedList *fl = ulistfmt_openResult(&status);
268 assertSuccess("ulistfmt_openResult", &status);
269
270 ulistfmt_formatStringsToResult(fmt, strs, lens, 2, fl, &status);
271 assertSuccess("ulistfmt_formatStringsToResult", &status);
272
273 const UFormattedValue *value = ulistfmt_resultAsValue(fl, &status);
274 assertSuccess("ulistfmt_resultAsValue", &status);
275
276 {
277 int32_t len;
278 const UChar *str = ufmtval_getString(value, &len, &status);
279 assertUEquals("TEST ufmtval_getString", u"A and ", str);
280 }
281
282 UConstrainedFieldPosition *fpos = ucfpos_open(&status);
283 assertSuccess("ucfpos_open", &status);
284
285 ucfpos_constrainField(fpos, UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, &status);
286 assertSuccess("ucfpos_constrainField", &status);
287
288 bool hasMore = ufmtval_nextPosition(value, fpos, &status);
289 assertSuccess("ufmtval_nextPosition", &status);
290 assertTrue("hasMore 1", hasMore);
291
292 int32_t beginIndex, endIndex;
293 ucfpos_getIndexes(fpos, &beginIndex, &endIndex, &status);
294 assertSuccess("ufmtval_nextPosition", &status);
295 assertIntEquals("TEST beginIndex", 0, beginIndex);
296 assertIntEquals("TEST endIndex", 1, endIndex);
297
298 hasMore = ufmtval_nextPosition(value, fpos, &status);
299 assertSuccess("ufmtval_nextPosition", &status);
300 assertTrue("hasMore 2", !hasMore);
301
302 ucfpos_close(fpos);
303 ulistfmt_closeResult(fl);
304 ulistfmt_close(fmt);
305 }
306
TestUList21871_B()307 static void TestUList21871_B() {
308 UErrorCode status = U_ZERO_ERROR;
309 UListFormatter *fmt = ulistfmt_openForType("en", ULISTFMT_TYPE_AND, ULISTFMT_WIDTH_WIDE, &status);
310 assertSuccess("ulistfmt_openForType", &status);
311
312 const UChar *strs[] = {u"", u"B"};
313 const int32_t lens[] = {0, 1};
314
315 UFormattedList *fl = ulistfmt_openResult(&status);
316 assertSuccess("ulistfmt_openResult", &status);
317
318 ulistfmt_formatStringsToResult(fmt, strs, lens, 2, fl, &status);
319 assertSuccess("ulistfmt_formatStringsToResult", &status);
320
321 const UFormattedValue *value = ulistfmt_resultAsValue(fl, &status);
322 assertSuccess("ulistfmt_resultAsValue", &status);
323
324 {
325 int32_t len;
326 const UChar *str = ufmtval_getString(value, &len, &status);
327 assertUEquals("TEST ufmtval_getString", u" and B", str);
328 }
329
330 UConstrainedFieldPosition *fpos = ucfpos_open(&status);
331 assertSuccess("ucfpos_open", &status);
332
333 ucfpos_constrainField(fpos, UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, &status);
334 assertSuccess("ucfpos_constrainField", &status);
335
336 bool hasMore = ufmtval_nextPosition(value, fpos, &status);
337 assertSuccess("ufmtval_nextPosition", &status);
338 assertTrue("hasMore 1", hasMore);
339
340 int32_t beginIndex, endIndex;
341 ucfpos_getIndexes(fpos, &beginIndex, &endIndex, &status);
342 assertSuccess("ucfpos_getIndexes", &status);
343 assertIntEquals("TEST beginIndex", 5, beginIndex);
344 assertIntEquals("TEST endIndex", 6, endIndex);
345
346 hasMore = ufmtval_nextPosition(value, fpos, &status);
347 assertSuccess("ufmtval_nextPosition", &status);
348 assertTrue("hasMore 2", !hasMore);
349
350 ucfpos_close(fpos);
351 ulistfmt_closeResult(fl);
352 ulistfmt_close(fmt);
353 }
354
355
356 #endif /* #if !UCONFIG_NO_FORMATTING */
357