1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 *******************************************************************************
5 *
6 * Copyright (C) 2002-2016, International Business Machines
7 * Corporation and others. All Rights Reserved.
8 *
9 *******************************************************************************
10 * file name: uenumtst.c
11 * encoding: UTF-8
12 * tab size: 8 (not used)
13 * indentation:2
14 *
15 * created on: 2002jul08
16 * created by: Vladimir Weinstein
17 */
18
19 #include "cintltst.h"
20 #include "uenumimp.h"
21 #include "cmemory.h"
22 #include "cstring.h"
23 #include "unicode/ustring.h"
24
25 static char quikBuf[256];
quikU2C(const UChar * str,int32_t len)26 static char* quikU2C(const UChar* str, int32_t len) {
27 u_UCharsToChars(str, quikBuf, len);
28 quikBuf[len] = 0;
29 return quikBuf;
30 }
31
32 static const char* test1[] = {
33 "first",
34 "second",
35 "third",
36 "fourth"
37 };
38
39 struct chArrayContext {
40 int32_t currIndex;
41 int32_t maxIndex;
42 char *currChar;
43 UChar *currUChar;
44 char **array;
45 };
46
47 typedef struct chArrayContext chArrayContext;
48
49 #define cont ((chArrayContext *)en->context)
50
51 static void U_CALLCONV
chArrayClose(UEnumeration * en)52 chArrayClose(UEnumeration *en) {
53 if(cont->currUChar != NULL) {
54 free(cont->currUChar);
55 cont->currUChar = NULL;
56 }
57 free(en);
58 }
59
60 static int32_t U_CALLCONV
chArrayCount(UEnumeration * en,UErrorCode * status)61 chArrayCount(UEnumeration *en, UErrorCode *status) {
62 (void)status; // suppress compiler warnings about unused variable
63 return cont->maxIndex;
64 }
65
66 static const UChar* U_CALLCONV
chArrayUNext(UEnumeration * en,int32_t * resultLength,UErrorCode * status)67 chArrayUNext(UEnumeration *en, int32_t *resultLength, UErrorCode *status) {
68 (void)status; // suppress compiler warnings about unused variable
69 if(cont->currIndex >= cont->maxIndex) {
70 return NULL;
71 }
72
73 if(cont->currUChar == NULL) {
74 cont->currUChar = (UChar *)malloc(1024*sizeof(UChar));
75 }
76
77 cont->currChar = (cont->array)[cont->currIndex];
78 *resultLength = (int32_t)strlen(cont->currChar);
79 u_charsToUChars(cont->currChar, cont->currUChar, *resultLength);
80 cont->currIndex++;
81 return cont->currUChar;
82 }
83
84 static const char* U_CALLCONV
chArrayNext(UEnumeration * en,int32_t * resultLength,UErrorCode * status)85 chArrayNext(UEnumeration *en, int32_t *resultLength, UErrorCode *status) {
86 (void)status; // suppress compiler warnings about unused variable
87 if(cont->currIndex >= cont->maxIndex) {
88 return NULL;
89 }
90
91 cont->currChar = (cont->array)[cont->currIndex];
92 *resultLength = (int32_t)strlen(cont->currChar);
93 cont->currIndex++;
94 return cont->currChar;
95 }
96
97 static void U_CALLCONV
chArrayReset(UEnumeration * en,UErrorCode * status)98 chArrayReset(UEnumeration *en, UErrorCode *status) {
99 (void)status; // suppress compiler warnings about unused variable
100 cont->currIndex = 0;
101 }
102
103 chArrayContext myCont = {
104 0, 0,
105 NULL, NULL,
106 NULL
107 };
108
109 UEnumeration chEnum = {
110 NULL,
111 &myCont,
112 chArrayClose,
113 chArrayCount,
114 chArrayUNext,
115 chArrayNext,
116 chArrayReset
117 };
118
119 static const UEnumeration emptyEnumerator = {
120 NULL,
121 NULL,
122 NULL,
123 NULL,
124 NULL,
125 NULL,
126 NULL,
127 };
128
129 static const UEnumeration emptyPartialEnumerator = {
130 NULL,
131 NULL,
132 NULL,
133 NULL,
134 uenum_unextDefault,
135 NULL,
136 NULL,
137 };
138
139 /********************************************************************/
140 static const UChar _first[] = {102,105,114,115,116,0}; /* "first" */
141 static const UChar _second[]= {115,101,99,111,110,100,0}; /* "second" */
142 static const UChar _third[] = {116,104,105,114,100,0}; /* "third" */
143 static const UChar _fourth[]= {102,111,117,114,116,104,0};/* "fourth" */
144
145 static const UChar* test2[] = {
146 _first, _second, _third, _fourth
147 };
148
149 struct uchArrayContext {
150 int32_t currIndex;
151 int32_t maxIndex;
152 UChar *currUChar;
153 UChar **array;
154 };
155
156 typedef struct uchArrayContext uchArrayContext;
157
158 #define ucont ((uchArrayContext *)en->context)
159
160 static void U_CALLCONV
uchArrayClose(UEnumeration * en)161 uchArrayClose(UEnumeration *en) {
162 free(en);
163 }
164
165 static int32_t U_CALLCONV
uchArrayCount(UEnumeration * en,UErrorCode * status)166 uchArrayCount(UEnumeration *en, UErrorCode *status) {
167 (void)status; // suppress compiler warnings about unused variable
168 return ucont->maxIndex;
169 }
170
171 static const UChar* U_CALLCONV
uchArrayUNext(UEnumeration * en,int32_t * resultLength,UErrorCode * status)172 uchArrayUNext(UEnumeration *en, int32_t *resultLength, UErrorCode *status) {
173 (void)status; // suppress compiler warnings about unused variable
174 if(ucont->currIndex >= ucont->maxIndex) {
175 return NULL;
176 }
177
178 ucont->currUChar = (ucont->array)[ucont->currIndex];
179 *resultLength = u_strlen(ucont->currUChar);
180 ucont->currIndex++;
181 return ucont->currUChar;
182 }
183
184 static void U_CALLCONV
uchArrayReset(UEnumeration * en,UErrorCode * status)185 uchArrayReset(UEnumeration *en, UErrorCode *status) {
186 (void)status; // suppress compiler warnings about unused variable
187 ucont->currIndex = 0;
188 }
189
190 uchArrayContext myUCont = {
191 0, 0,
192 NULL, NULL
193 };
194
195 UEnumeration uchEnum = {
196 NULL,
197 &myUCont,
198 uchArrayClose,
199 uchArrayCount,
200 uchArrayUNext,
201 uenum_nextDefault,
202 uchArrayReset
203 };
204
205 /********************************************************************/
206
getchArrayEnum(const char ** source,int32_t size)207 static UEnumeration *getchArrayEnum(const char** source, int32_t size) {
208 UEnumeration *en = (UEnumeration *)malloc(sizeof(UEnumeration));
209 memcpy(en, &chEnum, sizeof(UEnumeration));
210 cont->array = (char **)source;
211 cont->maxIndex = size;
212 return en;
213 }
214
EnumerationTest(void)215 static void EnumerationTest(void) {
216 UErrorCode status = U_ZERO_ERROR;
217 int32_t len = 0;
218 UEnumeration *en = getchArrayEnum(test1, UPRV_LENGTHOF(test1));
219 const char *string = NULL;
220 const UChar *uString = NULL;
221 while ((string = uenum_next(en, &len, &status))) {
222 log_verbose("read \"%s\", length %i\n", string, len);
223 }
224 uenum_reset(en, &status);
225 while ((uString = uenum_unext(en, &len, &status))) {
226 log_verbose("read \"%s\" (UChar), length %i\n", quikU2C(uString, len), len);
227 }
228
229 uenum_close(en);
230 }
231
EmptyEnumerationTest(void)232 static void EmptyEnumerationTest(void) {
233 UErrorCode status = U_ZERO_ERROR;
234 UEnumeration *emptyEnum = uprv_malloc(sizeof(UEnumeration));
235
236 uprv_memcpy(emptyEnum, &emptyEnumerator, sizeof(UEnumeration));
237 if (uenum_count(emptyEnum, &status) != -1 || status != U_UNSUPPORTED_ERROR) {
238 log_err("uenum_count failed\n");
239 }
240 status = U_ZERO_ERROR;
241 if (uenum_next(emptyEnum, NULL, &status) != NULL || status != U_UNSUPPORTED_ERROR) {
242 log_err("uenum_next failed\n");
243 }
244 status = U_ZERO_ERROR;
245 if (uenum_unext(emptyEnum, NULL, &status) != NULL || status != U_UNSUPPORTED_ERROR) {
246 log_err("uenum_unext failed\n");
247 }
248 status = U_ZERO_ERROR;
249 uenum_reset(emptyEnum, &status);
250 if (status != U_UNSUPPORTED_ERROR) {
251 log_err("uenum_reset failed\n");
252 }
253 uenum_close(emptyEnum);
254
255 status = U_ZERO_ERROR;
256 if (uenum_next(NULL, NULL, &status) != NULL || status != U_ZERO_ERROR) {
257 log_err("uenum_next(NULL) failed\n");
258 }
259 status = U_ZERO_ERROR;
260 if (uenum_unext(NULL, NULL, &status) != NULL || status != U_ZERO_ERROR) {
261 log_err("uenum_unext(NULL) failed\n");
262 }
263 status = U_ZERO_ERROR;
264 uenum_reset(NULL, &status);
265 if (status != U_ZERO_ERROR) {
266 log_err("uenum_reset(NULL) failed\n");
267 }
268
269 emptyEnum = uprv_malloc(sizeof(UEnumeration));
270 uprv_memcpy(emptyEnum, &emptyPartialEnumerator, sizeof(UEnumeration));
271 status = U_ZERO_ERROR;
272 if (uenum_unext(emptyEnum, NULL, &status) != NULL || status != U_UNSUPPORTED_ERROR) {
273 log_err("partial uenum_unext failed\n");
274 }
275 uenum_close(emptyEnum);
276 }
277
getuchArrayEnum(const UChar ** source,int32_t size)278 static UEnumeration *getuchArrayEnum(const UChar** source, int32_t size) {
279 UEnumeration *en = (UEnumeration *)malloc(sizeof(UEnumeration));
280 memcpy(en, &uchEnum, sizeof(UEnumeration));
281 ucont->array = (UChar **)source;
282 ucont->maxIndex = size;
283 return en;
284 }
285
DefaultNextTest(void)286 static void DefaultNextTest(void) {
287 UErrorCode status = U_ZERO_ERROR;
288 int32_t len = 0;
289 UEnumeration *en = getuchArrayEnum(test2, UPRV_LENGTHOF(test2));
290 const char *string = NULL;
291 const UChar *uString = NULL;
292 while ((uString = uenum_unext(en, &len, &status))) {
293 log_verbose("read \"%s\" (UChar), length %i\n", quikU2C(uString, len), len);
294 }
295 if (U_FAILURE(status)) {
296 log_err("FAIL: uenum_unext => %s\n", u_errorName(status));
297 }
298 uenum_reset(en, &status);
299 while ((string = uenum_next(en, &len, &status))) {
300 log_verbose("read \"%s\", length %i\n", string, len);
301 }
302 if (U_FAILURE(status)) {
303 log_err("FAIL: uenum_next => %s\n", u_errorName(status));
304 }
305
306 uenum_close(en);
307 }
308
verifyEnumeration(int line,UEnumeration * u,const char * const * compareToChar,const UChar * const * compareToUChar,int32_t expect_count)309 static void verifyEnumeration(int line, UEnumeration *u, const char * const * compareToChar, const UChar * const * compareToUChar, int32_t expect_count) {
310 UErrorCode status = U_ZERO_ERROR;
311 int32_t got_count,i,len;
312 const char *c;
313 UChar buf[1024];
314
315 log_verbose("%s:%d: verifying enumeration..\n", __FILE__, line);
316
317 uenum_reset(u, &status);
318 if(U_FAILURE(status)) {
319 log_err("%s:%d: FAIL: could not reset char strings enumeration: %s\n", __FILE__, line, u_errorName(status));
320 return;
321 }
322
323 got_count = uenum_count(u, &status);
324 if(U_FAILURE(status)) {
325 log_err("%s:%d: FAIL: could not count char strings enumeration: %s\n", __FILE__, line, u_errorName(status));
326 return;
327 }
328
329 if(got_count!=expect_count) {
330 log_err("%s:%d: FAIL: expect count %d got %d\n", __FILE__, line, expect_count, got_count);
331 } else {
332 log_verbose("%s:%d: OK: got count %d\n", __FILE__, line, got_count);
333 }
334
335 if(compareToChar!=NULL) { /* else, not invariant */
336 for(i=0;i<got_count;i++) {
337 c = uenum_next(u,&len, &status);
338 if(U_FAILURE(status)) {
339 log_err("%s:%d: FAIL: could not iterate to next after %d: %s\n", __FILE__, line, i, u_errorName(status));
340 return;
341 }
342 if(c==NULL) {
343 log_err("%s:%d: FAIL: got NULL for next after %d: %s\n", __FILE__, line, i, u_errorName(status));
344 return;
345 }
346
347 if(strcmp(c,compareToChar[i])) {
348 log_err("%s:%d: FAIL: string #%d expected '%s' got '%s'\n", __FILE__, line, i, compareToChar[i], c);
349 } else {
350 log_verbose("%s:%d: OK: string #%d got '%s'\n", __FILE__, line, i, c);
351 }
352
353 if(len!=(int32_t)strlen(compareToChar[i])) {
354 log_err("%s:%d: FAIL: string #%d expected len %d got %d\n", __FILE__, line, i, strlen(compareToChar[i]), len);
355 } else {
356 log_verbose("%s:%d: OK: string #%d got len %d\n", __FILE__, line, i, len);
357 }
358 }
359 }
360
361 /* now try U */
362 uenum_reset(u, &status);
363 if(U_FAILURE(status)) {
364 log_err("%s:%d: FAIL: could not reset again char strings enumeration: %s\n", __FILE__, line, u_errorName(status));
365 return;
366 }
367
368 for(i=0;i<got_count;i++) {
369 const UChar *ustr = uenum_unext(u,&len, &status);
370 if(U_FAILURE(status)) {
371 log_err("%s:%d: FAIL: could not iterate to unext after %d: %s\n", __FILE__, line, i, u_errorName(status));
372 return;
373 }
374 if(ustr==NULL) {
375 log_err("%s:%d: FAIL: got NULL for unext after %d: %s\n", __FILE__, line, i, u_errorName(status));
376 return;
377 }
378 if(compareToChar!=NULL) {
379 u_charsToUChars(compareToChar[i], buf, (int32_t)strlen(compareToChar[i])+1);
380 if(u_strncmp(ustr,buf,len)) {
381 int j;
382 log_err("%s:%d: FAIL: ustring #%d expected '%s' got '%s'\n", __FILE__, line, i, compareToChar[i], austrdup(ustr));
383 for(j=0;ustr[j]&&buf[j];j++) {
384 log_verbose(" @ %d\t<U+%04X> vs <U+%04X>\n", j, ustr[j],buf[j]);
385 }
386 } else {
387 log_verbose("%s:%d: OK: ustring #%d got '%s'\n", __FILE__, line, i, compareToChar[i]);
388 }
389
390 if(len!=(int32_t)strlen(compareToChar[i])) {
391 log_err("%s:%d: FAIL: ustring #%d expected len %d got %d\n", __FILE__, line, i, strlen(compareToChar[i]), len);
392 } else {
393 log_verbose("%s:%d: OK: ustring #%d got len %d\n", __FILE__, line, i, len);
394 }
395 }
396
397 if(compareToUChar!=NULL) {
398 if(u_strcmp(ustr,compareToUChar[i])) {
399 int j;
400 log_err("%s:%d: FAIL: ustring #%d expected '%s' got '%s'\n", __FILE__, line, i, austrdup(compareToUChar[i]), austrdup(ustr));
401 for(j=0;ustr[j]&&compareToUChar[j];j++) {
402 log_verbose(" @ %d\t<U+%04X> vs <U+%04X>\n", j, ustr[j],compareToUChar[j]);
403 }
404 } else {
405 log_verbose("%s:%d: OK: ustring #%d got '%s'\n", __FILE__, line, i, austrdup(compareToUChar[i]));
406 }
407
408 if(len!=u_strlen(compareToUChar[i])) {
409 log_err("%s:%d: FAIL: ustring #%d expected len %d got %d\n", __FILE__, line, i, u_strlen(compareToUChar[i]), len);
410 } else {
411 log_verbose("%s:%d: OK: ustring #%d got len %d\n", __FILE__, line, i, len);
412 }
413 }
414 }
415 }
416
417
418
419
420
TestCharStringsEnumeration(void)421 static void TestCharStringsEnumeration(void) {
422 UErrorCode status = U_ZERO_ERROR;
423
424 /* //! [uenum_openCharStringsEnumeration] */
425 const char* strings[] = { "Firstly", "Secondly", "Thirdly", "Fourthly" };
426 UEnumeration *u = uenum_openCharStringsEnumeration(strings, 4, &status);
427 /* //! [uenum_openCharStringsEnumeration] */
428 if(U_FAILURE(status)) {
429 log_err("FAIL: could not open char strings enumeration: %s\n", u_errorName(status));
430 return;
431 }
432
433 verifyEnumeration(__LINE__, u, strings, NULL, 4);
434
435 uenum_close(u);
436 }
437
TestUCharStringsEnumeration(void)438 static void TestUCharStringsEnumeration(void) {
439 UErrorCode status = U_ZERO_ERROR;
440 /* //! [uenum_openUCharStringsEnumeration] */
441 static const UChar nko_1[] = {0x07c1,0}, nko_2[] = {0x07c2,0}, nko_3[] = {0x07c3,0}, nko_4[] = {0x07c4,0};
442 static const UChar* ustrings[] = { nko_1, nko_2, nko_3, nko_4 };
443 UEnumeration *u = uenum_openUCharStringsEnumeration(ustrings, 4, &status);
444 /* //! [uenum_openUCharStringsEnumeration] */
445 if(U_FAILURE(status)) {
446 log_err("FAIL: could not open uchar strings enumeration: %s\n", u_errorName(status));
447 return;
448 }
449
450 verifyEnumeration(__LINE__, u, NULL, ustrings, 4);
451 uenum_close(u);
452
453
454 u = uenum_openUCharStringsEnumeration(test2, 4, &status);
455 if(U_FAILURE(status)) {
456 log_err("FAIL: could not reopen uchar strings enumeration: %s\n", u_errorName(status));
457 return;
458 }
459 verifyEnumeration(__LINE__, u, test1, NULL, 4); /* same string */
460 uenum_close(u);
461
462 }
463
464 void addEnumerationTest(TestNode** root);
465
addEnumerationTest(TestNode ** root)466 void addEnumerationTest(TestNode** root)
467 {
468 addTest(root, &EnumerationTest, "tsutil/uenumtst/EnumerationTest");
469 addTest(root, &EmptyEnumerationTest, "tsutil/uenumtst/EmptyEnumerationTest");
470 addTest(root, &DefaultNextTest, "tsutil/uenumtst/DefaultNextTest");
471 addTest(root, &TestCharStringsEnumeration, "tsutil/uenumtst/TestCharStringsEnumeration");
472 addTest(root, &TestUCharStringsEnumeration, "tsutil/uenumtst/TestUCharStringsEnumeration");
473 }
474