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 
24 void addUListFmtTest(TestNode** root);
25 
26 #define TESTCASE(x) addTest(root, &x, "tsformat/ulistfmttest/" #x)
27 
addUListFmtTest(TestNode ** root)28 void addUListFmtTest(TestNode** root)
29 {
30     TESTCASE(TestUListFmt);
31     TESTCASE(TestUListFmtToValue);
32     TESTCASE(TestUListOpenStyled);
33 }
34 
35 static const UChar str0[] = { 0x41,0 }; /* "A" */
36 static const UChar str1[] = { 0x42,0x62,0 }; /* "Bb" */
37 static const UChar str2[] = { 0x43,0x63,0x63,0 }; /* "Ccc" */
38 static const UChar str3[] = { 0x44,0x64,0x64,0x64,0 }; /* "Dddd" */
39 static const UChar str4[] = { 0x45,0x65,0x65,0x65,0x65,0 }; /* "Eeeee" */
40 static const UChar* strings[] =            { str0, str1, str2, str3, str4 };
41 static const int32_t stringLengths[]  =    {    1,    2,    3,    4,    5 };
42 static const int32_t stringLengthsNeg[] = {   -1,   -1,   -1,   -1,   -1 };
43 
44 typedef struct {
45   const char * locale;
46   int32_t stringCount;
47   const char *expectedResult; /* invariant chars + escaped Unicode */
48 } ListFmtTestEntry;
49 
50 static ListFmtTestEntry listFmtTestEntries[] = {
51     /* locale stringCount expectedResult */
52     { "en" ,  5,          "A, Bb, Ccc, Dddd, and Eeeee" },
53     { "en" ,  2,          "A and Bb" },
54     { "de" ,  5,          "A, Bb, Ccc, Dddd und Eeeee" },
55     { "de" ,  2,          "A und Bb" },
56     { "ja" ,  5,          "A\\u3001Bb\\u3001Ccc\\u3001Dddd\\u3001Eeeee" },
57     { "ja" ,  2,          "A\\u3001Bb" },
58     { "zh" ,  5,          "A\\u3001Bb\\u3001Ccc\\u3001Dddd\\u548CEeeee" },
59     { "zh" ,  2,          "A\\u548CBb" },
60     { NULL ,  0,          NULL } /* terminator */
61     };
62 
63 enum {
64   kUBufMax = 128,
65   kBBufMax = 256
66 };
67 
TestUListFmt()68 static void TestUListFmt() {
69     const ListFmtTestEntry * lftep;
70     for (lftep = listFmtTestEntries; lftep->locale != NULL ; lftep++ ) {
71         UErrorCode status = U_ZERO_ERROR;
72         UListFormatter *listfmt = ulistfmt_open(lftep->locale, &status);
73         if ( U_FAILURE(status) ) {
74             log_data_err("ERROR: ulistfmt_open fails for locale %s, status %s\n", lftep->locale, u_errorName(status));
75         } else {
76             UChar ubufActual[kUBufMax];
77             int32_t ulenActual = ulistfmt_format(listfmt, strings, stringLengths, lftep->stringCount, ubufActual, kUBufMax, &status);
78             if ( U_FAILURE(status) ) {
79                 log_err("ERROR: ulistfmt_format fails for locale %s count %d (real lengths), status %s\n", lftep->locale, lftep->stringCount, u_errorName(status));
80             } else {
81                 UChar ubufExpected[kUBufMax];
82                 int32_t ulenExpected = u_unescape(lftep->expectedResult, ubufExpected, kUBufMax);
83                 if (ulenActual != ulenExpected || u_strncmp(ubufActual, ubufExpected, ulenExpected) != 0) {
84                     log_err("ERROR: ulistfmt_format for locale %s count %d (real lengths), actual \"%s\" != expected \"%s\"\n", lftep->locale,
85                             lftep->stringCount, aescstrdup(ubufActual, ulenActual), aescstrdup(ubufExpected, ulenExpected));
86                 }
87             }
88             /* try again with all lengths -1 */
89             status = U_ZERO_ERROR;
90             ulenActual = ulistfmt_format(listfmt, strings, stringLengthsNeg, lftep->stringCount, ubufActual, kUBufMax, &status);
91             if ( U_FAILURE(status) ) {
92                 log_err("ERROR: ulistfmt_format fails for locale %s count %d (-1 lengths), status %s\n", lftep->locale, lftep->stringCount, u_errorName(status));
93             } else {
94                 UChar ubufExpected[kUBufMax];
95                 int32_t ulenExpected = u_unescape(lftep->expectedResult, ubufExpected, kUBufMax);
96                 if (ulenActual != ulenExpected || u_strncmp(ubufActual, ubufExpected, ulenExpected) != 0) {
97                     log_err("ERROR: ulistfmt_format for locale %s count %d (-1   lengths), actual \"%s\" != expected \"%s\"\n", lftep->locale,
98                             lftep->stringCount, aescstrdup(ubufActual, ulenActual), aescstrdup(ubufExpected, ulenExpected));
99                 }
100             }
101             /* try again with NULL lengths */
102             status = U_ZERO_ERROR;
103             ulenActual = ulistfmt_format(listfmt, strings, NULL, lftep->stringCount, ubufActual, kUBufMax, &status);
104             if ( U_FAILURE(status) ) {
105                 log_err("ERROR: ulistfmt_format fails for locale %s count %d (NULL lengths), status %s\n", lftep->locale, lftep->stringCount, u_errorName(status));
106             } else {
107                 UChar ubufExpected[kUBufMax];
108                 int32_t ulenExpected = u_unescape(lftep->expectedResult, ubufExpected, kUBufMax);
109                 if (ulenActual != ulenExpected || u_strncmp(ubufActual, ubufExpected, ulenExpected) != 0) {
110                     log_err("ERROR: ulistfmt_format for locale %s count %d (NULL lengths), actual \"%s\" != expected \"%s\"\n", lftep->locale,
111                             lftep->stringCount, aescstrdup(ubufActual, ulenActual), aescstrdup(ubufExpected, ulenExpected));
112                 }
113             }
114 
115             /* try calls that should return error */
116             status = U_ZERO_ERROR;
117             ulenActual = ulistfmt_format(listfmt, NULL, NULL, lftep->stringCount, ubufActual, kUBufMax, &status);
118             if (status != U_ILLEGAL_ARGUMENT_ERROR || ulenActual > 0) {
119                 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,
120                         lftep->stringCount, u_errorName(status), ulenActual);
121             }
122             status = U_ZERO_ERROR;
123             ulenActual = ulistfmt_format(listfmt, strings, NULL, lftep->stringCount, NULL, kUBufMax, &status);
124             if (status != U_ILLEGAL_ARGUMENT_ERROR || ulenActual > 0) {
125                 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,
126                         lftep->stringCount, u_errorName(status), ulenActual);
127             }
128 
129             ulistfmt_close(listfmt);
130         }
131     }
132 }
133 
TestUListFmtToValue()134 static void TestUListFmtToValue() {
135     UErrorCode ec = U_ZERO_ERROR;
136     UListFormatter* fmt = ulistfmt_open("en", &ec);
137     UFormattedList* fl = ulistfmt_openResult(&ec);
138     assertSuccess("Opening", &ec);
139 
140     {
141         const char* message = "Field position test 1";
142         const UChar* expectedString = u"hello, wonderful, and world";
143         const UChar* inputs[] = {
144             u"hello",
145             u"wonderful",
146             u"world"
147         };
148         ulistfmt_formatStringsToResult(fmt, inputs, NULL, UPRV_LENGTHOF(inputs), fl, &ec);
149         assertSuccess("Formatting", &ec);
150         static const UFieldPositionWithCategory expectedFieldPositions[] = {
151             // field, begin index, end index
152             {UFIELD_CATEGORY_LIST_SPAN, 0, 0, 5},
153             {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 0, 5},
154             {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 5, 7},
155             {UFIELD_CATEGORY_LIST_SPAN, 1, 7, 16},
156             {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 7, 16},
157             {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 16, 22},
158             {UFIELD_CATEGORY_LIST_SPAN, 2, 22, 27},
159             {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 22, 27}};
160         checkMixedFormattedValue(
161             message,
162             ulistfmt_resultAsValue(fl, &ec),
163             expectedString,
164             expectedFieldPositions,
165             UPRV_LENGTHOF(expectedFieldPositions));
166     }
167     {
168         const char* message = "Field position test 1";
169         const UChar* expectedString = u"A, B, C, D, E, F, and G";
170         const UChar* inputs[] = {
171             u"A",
172             u"B",
173             u"C",
174             u"D",
175             u"E",
176             u"F",
177             u"G"
178         };
179         ulistfmt_formatStringsToResult(fmt, inputs, NULL, UPRV_LENGTHOF(inputs), fl, &ec);
180         assertSuccess("Formatting", &ec);
181         static const UFieldPositionWithCategory expectedFieldPositions[] = {
182             // field, begin index, end index
183             {UFIELD_CATEGORY_LIST_SPAN, 0, 0,  1},
184             {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 0,  1},
185             {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 1,  3},
186             {UFIELD_CATEGORY_LIST_SPAN, 1, 3,  4},
187             {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 3,  4},
188             {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 4,  6},
189             {UFIELD_CATEGORY_LIST_SPAN, 2, 6,  7},
190             {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 6,  7},
191             {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 7,  9},
192             {UFIELD_CATEGORY_LIST_SPAN, 3, 9,  10},
193             {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 9,  10},
194             {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 10, 12},
195             {UFIELD_CATEGORY_LIST_SPAN, 4, 12, 13},
196             {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 12, 13},
197             {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 13, 15},
198             {UFIELD_CATEGORY_LIST_SPAN, 5, 15, 16},
199             {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 15, 16},
200             {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 16, 22},
201             {UFIELD_CATEGORY_LIST_SPAN, 6, 22, 23},
202             {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 22, 23}};
203         checkMixedFormattedValue(
204             message,
205             ulistfmt_resultAsValue(fl, &ec),
206             expectedString,
207             expectedFieldPositions,
208             UPRV_LENGTHOF(expectedFieldPositions));
209     }
210 
211     ulistfmt_close(fmt);
212     ulistfmt_closeResult(fl);
213 }
214 
TestUListOpenStyled()215 static void TestUListOpenStyled() {
216     UErrorCode ec = U_ZERO_ERROR;
217     UListFormatter* fmt = ulistfmt_openForType("en", ULISTFMT_TYPE_OR, ULISTFMT_WIDTH_SHORT, &ec);
218     UFormattedList* fl = ulistfmt_openResult(&ec);
219     assertSuccess("Opening", &ec);
220 
221     {
222         const char* message = "openStyled test 1";
223         const UChar* expectedString = u"A, B, or C";
224         const UChar* inputs[] = {
225             u"A",
226             u"B",
227             u"C",
228         };
229         ulistfmt_formatStringsToResult(fmt, inputs, NULL, UPRV_LENGTHOF(inputs), fl, &ec);
230         assertSuccess("Formatting", &ec);
231         static const UFieldPositionWithCategory expectedFieldPositions[] = {
232             // field, begin index, end index
233             {UFIELD_CATEGORY_LIST_SPAN, 0, 0,  1},
234             {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 0,  1},
235             {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 1,  3},
236             {UFIELD_CATEGORY_LIST_SPAN, 1, 3,  4},
237             {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 3,  4},
238             {UFIELD_CATEGORY_LIST, ULISTFMT_LITERAL_FIELD, 4,  9},
239             {UFIELD_CATEGORY_LIST_SPAN, 2, 9, 10},
240             {UFIELD_CATEGORY_LIST, ULISTFMT_ELEMENT_FIELD, 9, 10}};
241         checkMixedFormattedValue(
242             message,
243             ulistfmt_resultAsValue(fl, &ec),
244             expectedString,
245             expectedFieldPositions,
246             UPRV_LENGTHOF(expectedFieldPositions));
247     }
248 
249     ulistfmt_close(fmt);
250     ulistfmt_closeResult(fl);
251 }
252 
253 
254 #endif /* #if !UCONFIG_NO_FORMATTING */
255