1/*
2*******************************************************************************
3*
4*   Copyright (C) 2002-2003, 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
300void addEnumerationTest(TestNode** root);
301
302void addEnumerationTest(TestNode** root)
303{
304    addTest(root, &EnumerationTest, "tsutil/uenumtst/EnumerationTest");
305    addTest(root, &EmptyEnumerationTest, "tsutil/uenumtst/EmptyEnumerationTest");
306    addTest(root, &DefaultNextTest, "tsutil/uenumtst/DefaultNextTest");
307}
308