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