• 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 *******************************************************************************
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