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