• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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