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