1 /*
2 ******************************************************************************
3 *
4 *   Copyright (C) 2001-2014, International Business Machines
5 *   Corporation and others.  All Rights Reserved.
6 *
7 ******************************************************************************
8 *   file name:  trietest.c
9 *   encoding:   US-ASCII
10 *   tab size:   8 (not used)
11 *   indentation:4
12 *
13 *   created on: 2008sep01 (starting from a copy of trietest.c)
14 *   created by: Markus W. Scherer
15 */
16 
17 #include <stdio.h>
18 #include "unicode/utypes.h"
19 #include "utrie2.h"
20 #include "utrie.h"
21 #include "cstring.h"
22 #include "cmemory.h"
23 #include "udataswp.h"
24 #include "cintltst.h"
25 
26 void addTrie2Test(TestNode** root);
27 
28 /* Values for setting possibly overlapping, out-of-order ranges of values */
29 typedef struct SetRange {
30     UChar32 start, limit;
31     uint32_t value;
32     UBool overwrite;
33 } SetRange;
34 
35 /*
36  * Values for testing:
37  * value is set from the previous boundary's limit to before
38  * this boundary's limit
39  *
40  * There must be an entry with limit 0 and the intialValue.
41  * It may be preceded by an entry with negative limit and the errorValue.
42  */
43 typedef struct CheckRange {
44     UChar32 limit;
45     uint32_t value;
46 } CheckRange;
47 
48 static int32_t
skipSpecialValues(const CheckRange checkRanges[],int32_t countCheckRanges)49 skipSpecialValues(const CheckRange checkRanges[], int32_t countCheckRanges) {
50     int32_t i;
51     for(i=0; i<countCheckRanges && checkRanges[i].limit<=0; ++i) {}
52     return i;
53 }
54 
55 static int32_t
getSpecialValues(const CheckRange checkRanges[],int32_t countCheckRanges,uint32_t * pInitialValue,uint32_t * pErrorValue)56 getSpecialValues(const CheckRange checkRanges[], int32_t countCheckRanges,
57                  uint32_t *pInitialValue, uint32_t *pErrorValue) {
58     int32_t i=0;
59     if(i<countCheckRanges && checkRanges[i].limit<0) {
60         *pErrorValue=checkRanges[i++].value;
61     } else {
62         *pErrorValue=0xbad;
63     }
64     if(i<countCheckRanges && checkRanges[i].limit==0) {
65         *pInitialValue=checkRanges[i++].value;
66     } else {
67         *pInitialValue=0;
68     }
69     return i;
70 }
71 
72 /* utrie2_enum() callback, modifies a value */
73 static uint32_t U_CALLCONV
testEnumValue(const void * context,uint32_t value)74 testEnumValue(const void *context, uint32_t value) {
75     return value^0x5555;
76 }
77 
78 /* utrie2_enum() callback, verifies a range */
79 static UBool U_CALLCONV
testEnumRange(const void * context,UChar32 start,UChar32 end,uint32_t value)80 testEnumRange(const void *context, UChar32 start, UChar32 end, uint32_t value) {
81     const CheckRange **pb=(const CheckRange **)context;
82     const CheckRange *b=(*pb)++;
83     UChar32 limit=end+1;
84 
85     value^=0x5555;
86     if(start!=(b-1)->limit || limit!=b->limit || value!=b->value) {
87         log_err("error: utrie2_enum() delivers wrong range [U+%04lx..U+%04lx].0x%lx instead of [U+%04lx..U+%04lx].0x%lx\n",
88             (long)start, (long)end, (long)value,
89             (long)(b-1)->limit, (long)b->limit-1, (long)b->value);
90     }
91     return TRUE;
92 }
93 
94 static void
testTrieEnum(const char * testName,const UTrie2 * trie,const CheckRange checkRanges[],int32_t countCheckRanges)95 testTrieEnum(const char *testName,
96              const UTrie2 *trie,
97              const CheckRange checkRanges[], int32_t countCheckRanges) {
98     /* skip over special values */
99     while(countCheckRanges>0 && checkRanges[0].limit<=0) {
100         ++checkRanges;
101         --countCheckRanges;
102     }
103     utrie2_enum(trie, testEnumValue, testEnumRange, &checkRanges);
104 }
105 
106 /* verify all expected values via UTRIE2_GETxx() */
107 static void
testTrieGetters(const char * testName,const UTrie2 * trie,UTrie2ValueBits valueBits,const CheckRange checkRanges[],int32_t countCheckRanges)108 testTrieGetters(const char *testName,
109                 const UTrie2 *trie, UTrie2ValueBits valueBits,
110                 const CheckRange checkRanges[], int32_t countCheckRanges) {
111     uint32_t initialValue, errorValue;
112     uint32_t value, value2;
113     UChar32 start, limit;
114     int32_t i, countSpecials;
115 
116     UBool isFrozen=utrie2_isFrozen(trie);
117     const char *const typeName= isFrozen ? "frozen trie" : "newTrie";
118 
119     countSpecials=getSpecialValues(checkRanges, countCheckRanges, &initialValue, &errorValue);
120 
121     start=0;
122     for(i=countSpecials; i<countCheckRanges; ++i) {
123         limit=checkRanges[i].limit;
124         value=checkRanges[i].value;
125 
126         while(start<limit) {
127             if(isFrozen) {
128                 if(start<=0xffff) {
129                     if(!U_IS_LEAD(start)) {
130                         if(valueBits==UTRIE2_16_VALUE_BITS) {
131                             value2=UTRIE2_GET16_FROM_U16_SINGLE_LEAD(trie, start);
132                         } else {
133                             value2=UTRIE2_GET32_FROM_U16_SINGLE_LEAD(trie, start);
134                         }
135                         if(value!=value2) {
136                             log_err("error: %s(%s).fromBMP(U+%04lx)==0x%lx instead of 0x%lx\n",
137                                     typeName, testName, (long)start, (long)value2, (long)value);
138                         }
139                     }
140                 } else {
141                     if(valueBits==UTRIE2_16_VALUE_BITS) {
142                         value2=UTRIE2_GET16_FROM_SUPP(trie, start);
143                     } else {
144                         value2=UTRIE2_GET32_FROM_SUPP(trie, start);
145                     }
146                     if(value!=value2) {
147                         log_err("error: %s(%s).fromSupp(U+%04lx)==0x%lx instead of 0x%lx\n",
148                                 typeName, testName, (long)start, (long)value2, (long)value);
149                     }
150                 }
151                 if(valueBits==UTRIE2_16_VALUE_BITS) {
152                     value2=UTRIE2_GET16(trie, start);
153                 } else {
154                     value2=UTRIE2_GET32(trie, start);
155                 }
156                 if(value!=value2) {
157                     log_err("error: %s(%s).get(U+%04lx)==0x%lx instead of 0x%lx\n",
158                             typeName, testName, (long)start, (long)value2, (long)value);
159                 }
160             }
161             value2=utrie2_get32(trie, start);
162             if(value!=value2) {
163                 log_err("error: %s(%s).get32(U+%04lx)==0x%lx instead of 0x%lx\n",
164                         typeName, testName, (long)start, (long)value2, (long)value);
165             }
166             ++start;
167         }
168     }
169 
170     if(isFrozen) {
171         /* test linear ASCII range from the data array pointer (access to "internal" field) */
172         start=0;
173         for(i=countSpecials; i<countCheckRanges && start<=0x7f; ++i) {
174             limit=checkRanges[i].limit;
175             value=checkRanges[i].value;
176 
177             while(start<limit && start<=0x7f) {
178                 if(valueBits==UTRIE2_16_VALUE_BITS) {
179                     value2=trie->data16[start];
180                 } else {
181                     value2=trie->data32[start];
182                 }
183                 if(value!=value2) {
184                     log_err("error: %s(%s).asciiData[U+%04lx]==0x%lx instead of 0x%lx\n",
185                             typeName, testName, (long)start, (long)value2, (long)value);
186                 }
187                 ++start;
188             }
189         }
190         while(start<=0xbf) {
191             if(valueBits==UTRIE2_16_VALUE_BITS) {
192                 value2=trie->data16[start];
193             } else {
194                 value2=trie->data32[start];
195             }
196             if(errorValue!=value2) {
197                 log_err("error: %s(%s).badData[U+%04lx]==0x%lx instead of 0x%lx\n",
198                         typeName, testName, (long)start, (long)value2, (long)errorValue);
199             }
200             ++start;
201         }
202     }
203 
204     if(0!=strncmp(testName, "dummy", 5) && 0!=strncmp(testName, "trie1", 5)) {
205         /* test values for lead surrogate code units */
206         for(start=0xd7ff; start<0xdc01; ++start) {
207             switch(start) {
208             case 0xd7ff:
209             case 0xdc00:
210                 value=errorValue;
211                 break;
212             case 0xd800:
213                 value=90;
214                 break;
215             case 0xd999:
216                 value=94;
217                 break;
218             case 0xdbff:
219                 value=99;
220                 break;
221             default:
222                 value=initialValue;
223                 break;
224             }
225             if(isFrozen && U_IS_LEAD(start)) {
226                 if(valueBits==UTRIE2_16_VALUE_BITS) {
227                     value2=UTRIE2_GET16_FROM_U16_SINGLE_LEAD(trie, start);
228                 } else {
229                     value2=UTRIE2_GET32_FROM_U16_SINGLE_LEAD(trie, start);
230                 }
231                 if(value2!=value) {
232                     log_err("error: %s(%s).LSCU(U+%04lx)==0x%lx instead of 0x%lx\n",
233                             typeName, testName, (long)start, (long)value2, (long)value);
234                 }
235             }
236             value2=utrie2_get32FromLeadSurrogateCodeUnit(trie, start);
237             if(value2!=value) {
238                 log_err("error: %s(%s).lscu(U+%04lx)==0x%lx instead of 0x%lx\n",
239                         typeName, testName, (long)start, (long)value2, (long)value);
240             }
241         }
242     }
243 
244     /* test errorValue */
245     if(isFrozen) {
246         if(valueBits==UTRIE2_16_VALUE_BITS) {
247             value=UTRIE2_GET16(trie, -1);
248             value2=UTRIE2_GET16(trie, 0x110000);
249         } else {
250             value=UTRIE2_GET32(trie, -1);
251             value2=UTRIE2_GET32(trie, 0x110000);
252         }
253         if(value!=errorValue || value2!=errorValue) {
254             log_err("error: %s(%s).get(out of range) != errorValue\n",
255                     typeName, testName);
256         }
257     }
258     value=utrie2_get32(trie, -1);
259     value2=utrie2_get32(trie, 0x110000);
260     if(value!=errorValue || value2!=errorValue) {
261         log_err("error: %s(%s).get32(out of range) != errorValue\n",
262                 typeName, testName);
263     }
264 }
265 
266 static void
testTrieUTF16(const char * testName,const UTrie2 * trie,UTrie2ValueBits valueBits,const CheckRange checkRanges[],int32_t countCheckRanges)267 testTrieUTF16(const char *testName,
268               const UTrie2 *trie, UTrie2ValueBits valueBits,
269               const CheckRange checkRanges[], int32_t countCheckRanges) {
270     UChar s[200];
271     uint32_t values[100];
272 
273     const UChar *p, *limit;
274 
275     uint32_t value;
276     UChar32 prevCP, c, c2;
277     int32_t i, length, sIndex, countValues;
278 
279     /* write a string */
280     prevCP=0;
281     length=countValues=0;
282     for(i=skipSpecialValues(checkRanges, countCheckRanges); i<countCheckRanges; ++i) {
283         value=checkRanges[i].value;
284         /* write three code points */
285         U16_APPEND_UNSAFE(s, length, prevCP);   /* start of the range */
286         values[countValues++]=value;
287         c=checkRanges[i].limit;
288         prevCP=(prevCP+c)/2;                    /* middle of the range */
289         U16_APPEND_UNSAFE(s, length, prevCP);
290         values[countValues++]=value;
291         prevCP=c;
292         --c;                                    /* end of the range */
293         U16_APPEND_UNSAFE(s, length, c);
294         values[countValues++]=value;
295     }
296     limit=s+length;
297 
298     /* try forward */
299     p=s;
300     i=0;
301     while(p<limit) {
302         sIndex=(int32_t)(p-s);
303         U16_NEXT(s, sIndex, length, c2);
304         c=0x33;
305         if(valueBits==UTRIE2_16_VALUE_BITS) {
306             UTRIE2_U16_NEXT16(trie, p, limit, c, value);
307         } else {
308             UTRIE2_U16_NEXT32(trie, p, limit, c, value);
309         }
310         if(value!=values[i]) {
311             log_err("error: wrong value from UTRIE2_NEXT(%s)(U+%04lx): 0x%lx instead of 0x%lx\n",
312                     testName, (long)c, (long)value, (long)values[i]);
313         }
314         if(c!=c2) {
315             log_err("error: wrong code point from UTRIE2_NEXT(%s): U+%04lx != U+%04lx\n",
316                     testName, (long)c, (long)c2);
317             continue;
318         }
319         ++i;
320     }
321 
322     /* try backward */
323     p=limit;
324     i=countValues;
325     while(s<p) {
326         --i;
327         sIndex=(int32_t)(p-s);
328         U16_PREV(s, 0, sIndex, c2);
329         c=0x33;
330         if(valueBits==UTRIE2_16_VALUE_BITS) {
331             UTRIE2_U16_PREV16(trie, s, p, c, value);
332         } else {
333             UTRIE2_U16_PREV32(trie, s, p, c, value);
334         }
335         if(value!=values[i]) {
336             log_err("error: wrong value from UTRIE2_PREV(%s)(U+%04lx): 0x%lx instead of 0x%lx\n",
337                     testName, (long)c, (long)value, (long)values[i]);
338         }
339         if(c!=c2) {
340             log_err("error: wrong code point from UTRIE2_PREV(%s): U+%04lx != U+%04lx\n",
341                     testName, c, c2);
342         }
343     }
344 }
345 
346 static void
testTrieUTF8(const char * testName,const UTrie2 * trie,UTrie2ValueBits valueBits,const CheckRange checkRanges[],int32_t countCheckRanges)347 testTrieUTF8(const char *testName,
348              const UTrie2 *trie, UTrie2ValueBits valueBits,
349              const CheckRange checkRanges[], int32_t countCheckRanges) {
350     static const uint8_t illegal[]={
351         0xc0, 0x80,                         /* non-shortest U+0000 */
352         0xc1, 0xbf,                         /* non-shortest U+007f */
353         0xc2,                               /* truncated */
354         0xe0, 0x90, 0x80,                   /* non-shortest U+0400 */
355         0xe0, 0xa0,                         /* truncated */
356         0xed, 0xa0, 0x80,                   /* lead surrogate U+d800 */
357         0xed, 0xbf, 0xbf,                   /* trail surrogate U+dfff */
358         0xf0, 0x8f, 0xbf, 0xbf,             /* non-shortest U+ffff */
359         0xf0, 0x90, 0x80,                   /* truncated */
360         0xf4, 0x90, 0x80, 0x80,             /* beyond-Unicode U+110000 */
361         0xf8, 0x80, 0x80, 0x80,             /* truncated */
362         0xf8, 0x80, 0x80, 0x80, 0x80,       /* 5-byte UTF-8 */
363         0xfd, 0xbf, 0xbf, 0xbf, 0xbf,       /* truncated */
364         0xfd, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, /* 6-byte UTF-8 */
365         0xfe,
366         0xff
367     };
368     uint8_t s[600];
369     uint32_t values[200];
370 
371     const uint8_t *p, *limit;
372 
373     uint32_t initialValue, errorValue;
374     uint32_t value, bytes;
375     UChar32 prevCP, c;
376     int32_t i, countSpecials, length, countValues;
377     int32_t prev8, i8;
378 
379     countSpecials=getSpecialValues(checkRanges, countCheckRanges, &initialValue, &errorValue);
380 
381     /* write a string */
382     prevCP=0;
383     length=countValues=0;
384     /* first a couple of trail bytes in lead position */
385     s[length++]=0x80;
386     values[countValues++]=errorValue;
387     s[length++]=0xbf;
388     values[countValues++]=errorValue;
389     prev8=i8=0;
390     for(i=countSpecials; i<countCheckRanges; ++i) {
391         value=checkRanges[i].value;
392         /* write three legal (or surrogate) code points */
393         U8_APPEND_UNSAFE(s, length, prevCP);    /* start of the range */
394         values[countValues++]=U_IS_SURROGATE(prevCP) ? errorValue : value;
395         c=checkRanges[i].limit;
396         prevCP=(prevCP+c)/2;                    /* middle of the range */
397         U8_APPEND_UNSAFE(s, length, prevCP);
398         values[countValues++]=U_IS_SURROGATE(prevCP) ? errorValue : value;
399         prevCP=c;
400         --c;                                    /* end of the range */
401         U8_APPEND_UNSAFE(s, length, c);
402         values[countValues++]=U_IS_SURROGATE(c) ? errorValue : value;
403         /* write an illegal byte sequence */
404         if(i8<sizeof(illegal)) {
405             U8_FWD_1(illegal, i8, sizeof(illegal));
406             while(prev8<i8) {
407                 s[length++]=illegal[prev8++];
408             }
409             values[countValues++]=errorValue;
410         }
411     }
412     /* write the remaining illegal byte sequences */
413     while(i8<sizeof(illegal)) {
414         U8_FWD_1(illegal, i8, sizeof(illegal));
415         while(prev8<i8) {
416             s[length++]=illegal[prev8++];
417         }
418         values[countValues++]=errorValue;
419     }
420     limit=s+length;
421 
422     /* try forward */
423     p=s;
424     i=0;
425     while(p<limit) {
426         prev8=i8=(int32_t)(p-s);
427         U8_NEXT(s, i8, length, c);
428         if(valueBits==UTRIE2_16_VALUE_BITS) {
429             UTRIE2_U8_NEXT16(trie, p, limit, value);
430         } else {
431             UTRIE2_U8_NEXT32(trie, p, limit, value);
432         }
433         bytes=0;
434         if(value!=values[i] || i8!=(p-s)) {
435             while(prev8<i8) {
436                 bytes=(bytes<<8)|s[prev8++];
437             }
438         }
439         if(value!=values[i]) {
440             log_err("error: wrong value from UTRIE2_U8_NEXT(%s)(%lx->U+%04lx): 0x%lx instead of 0x%lx\n",
441                     testName, (unsigned long)bytes, (long)c, (long)value, (long)values[i]);
442         }
443         if(i8!=(p-s)) {
444             log_err("error: wrong end index from UTRIE2_U8_NEXT(%s)(%lx->U+%04lx): %ld != %ld\n",
445                     testName, (unsigned long)bytes, (long)c, (long)(p-s), (long)i8);
446             continue;
447         }
448         ++i;
449     }
450 
451     /* try backward */
452     p=limit;
453     i=countValues;
454     while(s<p) {
455         --i;
456         prev8=i8=(int32_t)(p-s);
457         U8_PREV(s, 0, i8, c);
458         if(valueBits==UTRIE2_16_VALUE_BITS) {
459             UTRIE2_U8_PREV16(trie, s, p, value);
460         } else {
461             UTRIE2_U8_PREV32(trie, s, p, value);
462         }
463         bytes=0;
464         if(value!=values[i] || i8!=(p-s)) {
465             int32_t k=i8;
466             while(k<prev8) {
467                 bytes=(bytes<<8)|s[k++];
468             }
469         }
470         if(value!=values[i]) {
471             log_err("error: wrong value from UTRIE2_U8_PREV(%s)(%lx->U+%04lx): 0x%lx instead of 0x%lx\n",
472                     testName, (unsigned long)bytes, (long)c, (long)value, (long)values[i]);
473         }
474         if(i8!=(p-s)) {
475             log_err("error: wrong end index from UTRIE2_U8_PREV(%s)(%lx->U+%04lx): %ld != %ld\n",
476                     testName, (unsigned long)bytes, (long)c, (long)(p-s), (long)i8);
477             continue;
478         }
479     }
480 }
481 
482 static void
testFrozenTrie(const char * testName,UTrie2 * trie,UTrie2ValueBits valueBits,const CheckRange checkRanges[],int32_t countCheckRanges)483 testFrozenTrie(const char *testName,
484                UTrie2 *trie, UTrie2ValueBits valueBits,
485                const CheckRange checkRanges[], int32_t countCheckRanges) {
486     UErrorCode errorCode;
487     uint32_t value, value2;
488 
489     if(!utrie2_isFrozen(trie)) {
490         log_err("error: utrie2_isFrozen(frozen %s) returned FALSE (not frozen)\n",
491                 testName);
492         return;
493     }
494 
495     testTrieGetters(testName, trie, valueBits, checkRanges, countCheckRanges);
496     testTrieEnum(testName, trie, checkRanges, countCheckRanges);
497     testTrieUTF16(testName, trie, valueBits, checkRanges, countCheckRanges);
498     testTrieUTF8(testName, trie, valueBits, checkRanges, countCheckRanges);
499 
500     errorCode=U_ZERO_ERROR;
501     value=utrie2_get32(trie, 1);
502     utrie2_set32(trie, 1, 234, &errorCode);
503     value2=utrie2_get32(trie, 1);
504     if(errorCode!=U_NO_WRITE_PERMISSION || value2!=value) {
505         log_err("error: utrie2_set32(frozen %s) failed: it set %s != U_NO_WRITE_PERMISSION\n",
506                 testName, u_errorName(errorCode));
507         return;
508     }
509 
510     errorCode=U_ZERO_ERROR;
511     utrie2_setRange32(trie, 1, 5, 234, TRUE, &errorCode);
512     value2=utrie2_get32(trie, 1);
513     if(errorCode!=U_NO_WRITE_PERMISSION || value2!=value) {
514         log_err("error: utrie2_setRange32(frozen %s) failed: it set %s != U_NO_WRITE_PERMISSION\n",
515                 testName, u_errorName(errorCode));
516         return;
517     }
518 
519     errorCode=U_ZERO_ERROR;
520     value=utrie2_get32FromLeadSurrogateCodeUnit(trie, 0xd801);
521     utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xd801, 234, &errorCode);
522     value2=utrie2_get32FromLeadSurrogateCodeUnit(trie, 0xd801);
523     if(errorCode!=U_NO_WRITE_PERMISSION || value2!=value) {
524         log_err("error: utrie2_set32ForLeadSurrogateCodeUnit(frozen %s) failed: "
525                 "it set %s != U_NO_WRITE_PERMISSION\n",
526                 testName, u_errorName(errorCode));
527         return;
528     }
529 }
530 
531 static void
testNewTrie(const char * testName,const UTrie2 * trie,const CheckRange checkRanges[],int32_t countCheckRanges)532 testNewTrie(const char *testName, const UTrie2 *trie,
533             const CheckRange checkRanges[], int32_t countCheckRanges) {
534     /* The valueBits are ignored for an unfrozen trie. */
535     testTrieGetters(testName, trie, UTRIE2_COUNT_VALUE_BITS, checkRanges, countCheckRanges);
536     testTrieEnum(testName, trie, checkRanges, countCheckRanges);
537 }
538 
539 static void
testTrieSerialize(const char * testName,UTrie2 * trie,UTrie2ValueBits valueBits,UBool withSwap,const CheckRange checkRanges[],int32_t countCheckRanges)540 testTrieSerialize(const char *testName,
541                   UTrie2 *trie, UTrie2ValueBits valueBits,
542                   UBool withSwap,
543                   const CheckRange checkRanges[], int32_t countCheckRanges) {
544     uint32_t storage[10000];
545     int32_t length1, length2, length3;
546     UTrie2ValueBits otherValueBits;
547     UErrorCode errorCode;
548 
549     /* clone the trie so that the caller can reuse the original */
550     errorCode=U_ZERO_ERROR;
551     trie=utrie2_clone(trie, &errorCode);
552     if(U_FAILURE(errorCode)) {
553         log_err("error: utrie2_clone(unfrozen %s) failed - %s\n",
554                 testName, u_errorName(errorCode));
555         return;
556     }
557 
558     /*
559      * This is not a loop, but simply a block that we can exit with "break"
560      * when something goes wrong.
561      */
562     do {
563         errorCode=U_ZERO_ERROR;
564         utrie2_serialize(trie, storage, sizeof(storage), &errorCode);
565         if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
566             log_err("error: utrie2_serialize(unfrozen %s) set %s != U_ILLEGAL_ARGUMENT_ERROR\n",
567                     testName, u_errorName(errorCode));
568             break;
569         }
570         errorCode=U_ZERO_ERROR;
571         utrie2_freeze(trie, valueBits, &errorCode);
572         if(U_FAILURE(errorCode) || !utrie2_isFrozen(trie)) {
573             log_err("error: utrie2_freeze(%s) failed: %s isFrozen: %d\n",
574                     testName, u_errorName(errorCode), utrie2_isFrozen(trie));
575             break;
576         }
577         otherValueBits= valueBits==UTRIE2_16_VALUE_BITS ? UTRIE2_32_VALUE_BITS : UTRIE2_16_VALUE_BITS;
578         utrie2_freeze(trie, otherValueBits, &errorCode);
579         if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
580             log_err("error: utrie2_freeze(already-frozen with other valueBits %s) "
581                     "set %s != U_ILLEGAL_ARGUMENT_ERROR\n",
582                     testName, u_errorName(errorCode));
583             break;
584         }
585         errorCode=U_ZERO_ERROR;
586         if(withSwap) {
587             /* clone a frozen trie */
588             UTrie2 *clone=utrie2_clone(trie, &errorCode);
589             if(U_FAILURE(errorCode)) {
590                 log_err("error: cloning a frozen UTrie2 failed (%s) - %s\n",
591                         testName, u_errorName(errorCode));
592                 errorCode=U_ZERO_ERROR;  /* continue with the original */
593             } else {
594                 utrie2_close(trie);
595                 trie=clone;
596             }
597         }
598         length1=utrie2_serialize(trie, NULL, 0, &errorCode);
599         if(errorCode!=U_BUFFER_OVERFLOW_ERROR) {
600             log_err("error: utrie2_serialize(%s) preflighting set %s != U_BUFFER_OVERFLOW_ERROR\n",
601                     testName, u_errorName(errorCode));
602             break;
603         }
604         errorCode=U_ZERO_ERROR;
605         length2=utrie2_serialize(trie, storage, sizeof(storage), &errorCode);
606         if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
607             log_err("error: utrie2_serialize(%s) needs more memory\n", testName);
608             break;
609         }
610         if(U_FAILURE(errorCode)) {
611             log_err("error: utrie2_serialize(%s) failed: %s\n", testName, u_errorName(errorCode));
612             break;
613         }
614         if(length1!=length2) {
615             log_err("error: trie serialization (%s) lengths different: "
616                     "preflight vs. serialize\n", testName);
617             break;
618         }
619 
620         testFrozenTrie(testName, trie, valueBits, checkRanges, countCheckRanges);
621         utrie2_close(trie);
622         trie=NULL;
623 
624         if(withSwap) {
625             uint32_t swapped[10000];
626             int32_t swappedLength;
627 
628             UDataSwapper *ds;
629 
630             /* swap to opposite-endian */
631             uprv_memset(swapped, 0x55, length2);
632             ds=udata_openSwapper(U_IS_BIG_ENDIAN, U_CHARSET_FAMILY,
633                                  !U_IS_BIG_ENDIAN, U_CHARSET_FAMILY, &errorCode);
634             swappedLength=utrie2_swap(ds, storage, -1, NULL, &errorCode);
635             if(U_FAILURE(errorCode) || swappedLength!=length2) {
636                 log_err("error: utrie2_swap(%s to OE preflighting) failed (%s) "
637                         "or before/after lengths different\n",
638                         testName, u_errorName(errorCode));
639                 udata_closeSwapper(ds);
640                 break;
641             }
642             swappedLength=utrie2_swap(ds, storage, length2, swapped, &errorCode);
643             udata_closeSwapper(ds);
644             if(U_FAILURE(errorCode) || swappedLength!=length2) {
645                 log_err("error: utrie2_swap(%s to OE) failed (%s) or before/after lengths different\n",
646                         testName, u_errorName(errorCode));
647                 break;
648             }
649 
650             /* swap back to platform-endian */
651             uprv_memset(storage, 0xaa, length2);
652             ds=udata_openSwapper(!U_IS_BIG_ENDIAN, U_CHARSET_FAMILY,
653                                  U_IS_BIG_ENDIAN, U_CHARSET_FAMILY, &errorCode);
654             swappedLength=utrie2_swap(ds, swapped, -1, NULL, &errorCode);
655             if(U_FAILURE(errorCode) || swappedLength!=length2) {
656                 log_err("error: utrie2_swap(%s to PE preflighting) failed (%s) "
657                         "or before/after lengths different\n",
658                         testName, u_errorName(errorCode));
659                 udata_closeSwapper(ds);
660                 break;
661             }
662             swappedLength=utrie2_swap(ds, swapped, length2, storage, &errorCode);
663             udata_closeSwapper(ds);
664             if(U_FAILURE(errorCode) || swappedLength!=length2) {
665                 log_err("error: utrie2_swap(%s to PE) failed (%s) or before/after lengths different\n",
666                         testName, u_errorName(errorCode));
667                 break;
668             }
669         }
670 
671         trie=utrie2_openFromSerialized(valueBits, storage, length2, &length3, &errorCode);
672         if(U_FAILURE(errorCode)) {
673             log_err("error: utrie2_openFromSerialized(%s) failed, %s\n", testName, u_errorName(errorCode));
674             break;
675         }
676         if((valueBits==UTRIE2_16_VALUE_BITS)!=(trie->data32==NULL)) {
677             log_err("error: trie serialization (%s) did not preserve 32-bitness\n", testName);
678             break;
679         }
680         if(length2!=length3) {
681             log_err("error: trie serialization (%s) lengths different: "
682                     "serialize vs. unserialize\n", testName);
683             break;
684         }
685         /* overwrite the storage that is not supposed to be needed */
686         uprv_memset((char *)storage+length3, 0xfa, (int32_t)(sizeof(storage)-length3));
687 
688         utrie2_freeze(trie, valueBits, &errorCode);
689         if(U_FAILURE(errorCode) || !utrie2_isFrozen(trie)) {
690             log_err("error: utrie2_freeze(unserialized %s) failed: %s isFrozen: %d\n",
691                     testName, u_errorName(errorCode), utrie2_isFrozen(trie));
692             break;
693         }
694         utrie2_freeze(trie, otherValueBits, &errorCode);
695         if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
696             log_err("error: utrie2_freeze(unserialized with other valueBits %s) "
697                     "set %s != U_ILLEGAL_ARGUMENT_ERROR\n",
698                     testName, u_errorName(errorCode));
699             break;
700         }
701         errorCode=U_ZERO_ERROR;
702         if(withSwap) {
703             /* clone an unserialized trie */
704             UTrie2 *clone=utrie2_clone(trie, &errorCode);
705             if(U_FAILURE(errorCode)) {
706                 log_err("error: utrie2_clone(unserialized %s) failed - %s\n",
707                         testName, u_errorName(errorCode));
708                 errorCode=U_ZERO_ERROR;
709                 /* no need to break: just test the original trie */
710             } else {
711                 utrie2_close(trie);
712                 trie=clone;
713                 uprv_memset(storage, 0, sizeof(storage));
714             }
715         }
716         testFrozenTrie(testName, trie, valueBits, checkRanges, countCheckRanges);
717         {
718             /* clone-as-thawed an unserialized trie */
719             UTrie2 *clone=utrie2_cloneAsThawed(trie, &errorCode);
720             if(U_FAILURE(errorCode) || utrie2_isFrozen(clone)) {
721                 log_err("error: utrie2_cloneAsThawed(unserialized %s) failed - "
722                         "%s (isFrozen: %d)\n",
723                         testName, u_errorName(errorCode), clone!=NULL && utrie2_isFrozen(trie));
724                 break;
725             } else {
726                 utrie2_close(trie);
727                 trie=clone;
728             }
729         }
730         {
731             uint32_t value, value2;
732 
733             value=utrie2_get32(trie, 0xa1);
734             utrie2_set32(trie, 0xa1, 789, &errorCode);
735             value2=utrie2_get32(trie, 0xa1);
736             utrie2_set32(trie, 0xa1, value, &errorCode);
737             if(U_FAILURE(errorCode) || value2!=789) {
738                 log_err("error: modifying a cloneAsThawed UTrie2 (%s) failed - %s\n",
739                         testName, u_errorName(errorCode));
740             }
741         }
742         testNewTrie(testName, trie, checkRanges, countCheckRanges);
743     } while(0);
744 
745     utrie2_close(trie);
746 }
747 
748 static UTrie2 *
testTrieSerializeAllValueBits(const char * testName,UTrie2 * trie,UBool withClone,const CheckRange checkRanges[],int32_t countCheckRanges)749 testTrieSerializeAllValueBits(const char *testName,
750                               UTrie2 *trie, UBool withClone,
751                               const CheckRange checkRanges[], int32_t countCheckRanges) {
752     char name[40];
753 
754     /* verify that all the expected values are in the unfrozen trie */
755     testNewTrie(testName, trie, checkRanges, countCheckRanges);
756 
757     /*
758      * Test with both valueBits serializations,
759      * and that utrie2_serialize() can be called multiple times.
760      */
761     uprv_strcpy(name, testName);
762     uprv_strcat(name, ".16");
763     testTrieSerialize(name, trie,
764                       UTRIE2_16_VALUE_BITS, withClone,
765                       checkRanges, countCheckRanges);
766 
767     if(withClone) {
768         /*
769          * try cloning after the first serialization;
770          * clone-as-thawed just to sometimes try it on an unfrozen trie
771          */
772         UErrorCode errorCode=U_ZERO_ERROR;
773         UTrie2 *clone=utrie2_cloneAsThawed(trie, &errorCode);
774         if(U_FAILURE(errorCode)) {
775             log_err("error: utrie2_cloneAsThawed(%s) after serialization failed - %s\n",
776                     testName, u_errorName(errorCode));
777         } else {
778             utrie2_close(trie);
779             trie=clone;
780 
781             testNewTrie(testName, trie, checkRanges, countCheckRanges);
782         }
783     }
784 
785     uprv_strcpy(name, testName);
786     uprv_strcat(name, ".32");
787     testTrieSerialize(name, trie,
788                       UTRIE2_32_VALUE_BITS, withClone,
789                       checkRanges, countCheckRanges);
790 
791     return trie; /* could be the clone */
792 }
793 
794 static UTrie2 *
makeTrieWithRanges(const char * testName,UBool withClone,const SetRange setRanges[],int32_t countSetRanges,const CheckRange checkRanges[],int32_t countCheckRanges)795 makeTrieWithRanges(const char *testName, UBool withClone,
796                    const SetRange setRanges[], int32_t countSetRanges,
797                    const CheckRange checkRanges[], int32_t countCheckRanges) {
798     UTrie2 *trie;
799     uint32_t initialValue, errorValue;
800     uint32_t value;
801     UChar32 start, limit;
802     int32_t i;
803     UErrorCode errorCode;
804     UBool overwrite;
805 
806     log_verbose("\ntesting Trie '%s'\n", testName);
807     errorCode=U_ZERO_ERROR;
808     getSpecialValues(checkRanges, countCheckRanges, &initialValue, &errorValue);
809     trie=utrie2_open(initialValue, errorValue, &errorCode);
810     if(U_FAILURE(errorCode)) {
811         log_err("error: utrie2_open(%s) failed: %s\n", testName, u_errorName(errorCode));
812         return NULL;
813     }
814 
815     /* set values from setRanges[] */
816     for(i=0; i<countSetRanges; ++i) {
817         if(withClone && i==countSetRanges/2) {
818             /* switch to a clone in the middle of setting values */
819             UTrie2 *clone=utrie2_clone(trie, &errorCode);
820             if(U_FAILURE(errorCode)) {
821                 log_err("error: utrie2_clone(%s) failed - %s\n",
822                         testName, u_errorName(errorCode));
823                 errorCode=U_ZERO_ERROR;  /* continue with the original */
824             } else {
825                 utrie2_close(trie);
826                 trie=clone;
827             }
828         }
829         start=setRanges[i].start;
830         limit=setRanges[i].limit;
831         value=setRanges[i].value;
832         overwrite=setRanges[i].overwrite;
833         if((limit-start)==1 && overwrite) {
834             utrie2_set32(trie, start, value, &errorCode);
835         } else {
836             utrie2_setRange32(trie, start, limit-1, value, overwrite, &errorCode);
837         }
838     }
839 
840     /* set some values for lead surrogate code units */
841     utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xd800, 90, &errorCode);
842     utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xd999, 94, &errorCode);
843     utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xdbff, 99, &errorCode);
844     if(U_SUCCESS(errorCode)) {
845         return trie;
846     } else {
847         log_err("error: setting values into a trie (%s) failed - %s\n",
848                 testName, u_errorName(errorCode));
849         utrie2_close(trie);
850         return NULL;
851     }
852 }
853 
854 static void
testTrieRanges(const char * testName,UBool withClone,const SetRange setRanges[],int32_t countSetRanges,const CheckRange checkRanges[],int32_t countCheckRanges)855 testTrieRanges(const char *testName, UBool withClone,
856                const SetRange setRanges[], int32_t countSetRanges,
857                const CheckRange checkRanges[], int32_t countCheckRanges) {
858     UTrie2 *trie=makeTrieWithRanges(testName, withClone,
859                                     setRanges, countSetRanges,
860                                     checkRanges, countCheckRanges);
861     if(trie!=NULL) {
862         trie=testTrieSerializeAllValueBits(testName, trie, withClone,
863                                            checkRanges, countCheckRanges);
864         utrie2_close(trie);
865     }
866 }
867 
868 /* test data ----------------------------------------------------------------*/
869 
870 /* set consecutive ranges, even with value 0 */
871 static const SetRange
872 setRanges1[]={
873     { 0,        0x40,     0,      FALSE },
874     { 0x40,     0xe7,     0x1234, FALSE },
875     { 0xe7,     0x3400,   0,      FALSE },
876     { 0x3400,   0x9fa6,   0x6162, FALSE },
877     { 0x9fa6,   0xda9e,   0x3132, FALSE },
878     { 0xdada,   0xeeee,   0x87ff, FALSE },
879     { 0xeeee,   0x11111,  1,      FALSE },
880     { 0x11111,  0x44444,  0x6162, FALSE },
881     { 0x44444,  0x60003,  0,      FALSE },
882     { 0xf0003,  0xf0004,  0xf,    FALSE },
883     { 0xf0004,  0xf0006,  0x10,   FALSE },
884     { 0xf0006,  0xf0007,  0x11,   FALSE },
885     { 0xf0007,  0xf0040,  0x12,   FALSE },
886     { 0xf0040,  0x110000, 0,      FALSE }
887 };
888 
889 static const CheckRange
890 checkRanges1[]={
891     { 0,        0 },
892     { 0x40,     0 },
893     { 0xe7,     0x1234 },
894     { 0x3400,   0 },
895     { 0x9fa6,   0x6162 },
896     { 0xda9e,   0x3132 },
897     { 0xdada,   0 },
898     { 0xeeee,   0x87ff },
899     { 0x11111,  1 },
900     { 0x44444,  0x6162 },
901     { 0xf0003,  0 },
902     { 0xf0004,  0xf },
903     { 0xf0006,  0x10 },
904     { 0xf0007,  0x11 },
905     { 0xf0040,  0x12 },
906     { 0x110000, 0 }
907 };
908 
909 /* set some interesting overlapping ranges */
910 static const SetRange
911 setRanges2[]={
912     { 0x21,     0x7f,     0x5555, TRUE },
913     { 0x2f800,  0x2fedc,  0x7a,   TRUE },
914     { 0x72,     0xdd,     3,      TRUE },
915     { 0xdd,     0xde,     4,      FALSE },
916     { 0x201,    0x240,    6,      TRUE },  /* 3 consecutive blocks with the same pattern but */
917     { 0x241,    0x280,    6,      TRUE },  /* discontiguous value ranges, testing utrie2_enum() */
918     { 0x281,    0x2c0,    6,      TRUE },
919     { 0x2f987,  0x2fa98,  5,      TRUE },
920     { 0x2f777,  0x2f883,  0,      TRUE },
921     { 0x2f900,  0x2ffaa,  1,      FALSE },
922     { 0x2ffaa,  0x2ffab,  2,      TRUE },
923     { 0x2ffbb,  0x2ffc0,  7,      TRUE }
924 };
925 
926 static const CheckRange
927 checkRanges2[]={
928     { 0,        0 },
929     { 0x21,     0 },
930     { 0x72,     0x5555 },
931     { 0xdd,     3 },
932     { 0xde,     4 },
933     { 0x201,    0 },
934     { 0x240,    6 },
935     { 0x241,    0 },
936     { 0x280,    6 },
937     { 0x281,    0 },
938     { 0x2c0,    6 },
939     { 0x2f883,  0 },
940     { 0x2f987,  0x7a },
941     { 0x2fa98,  5 },
942     { 0x2fedc,  0x7a },
943     { 0x2ffaa,  1 },
944     { 0x2ffab,  2 },
945     { 0x2ffbb,  0 },
946     { 0x2ffc0,  7 },
947     { 0x110000, 0 }
948 };
949 
950 static const CheckRange
951 checkRanges2_d800[]={
952     { 0x10000,  0 },
953     { 0x10400,  0 }
954 };
955 
956 static const CheckRange
957 checkRanges2_d87e[]={
958     { 0x2f800,  6 },
959     { 0x2f883,  0 },
960     { 0x2f987,  0x7a },
961     { 0x2fa98,  5 },
962     { 0x2fc00,  0x7a }
963 };
964 
965 static const CheckRange
966 checkRanges2_d87f[]={
967     { 0x2fc00,  0 },
968     { 0x2fedc,  0x7a },
969     { 0x2ffaa,  1 },
970     { 0x2ffab,  2 },
971     { 0x2ffbb,  0 },
972     { 0x2ffc0,  7 },
973     { 0x30000,  0 }
974 };
975 
976 static const CheckRange
977 checkRanges2_dbff[]={
978     { 0x10fc00, 0 },
979     { 0x110000, 0 }
980 };
981 
982 /* use a non-zero initial value */
983 static const SetRange
984 setRanges3[]={
985     { 0x31,     0xa4,     1, FALSE },
986     { 0x3400,   0x6789,   2, FALSE },
987     { 0x8000,   0x89ab,   9, TRUE },
988     { 0x9000,   0xa000,   4, TRUE },
989     { 0xabcd,   0xbcde,   3, TRUE },
990     { 0x55555,  0x110000, 6, TRUE },  /* highStart<U+ffff with non-initialValue */
991     { 0xcccc,   0x55555,  6, TRUE }
992 };
993 
994 static const CheckRange
995 checkRanges3[]={
996     { 0,        9 },  /* non-zero initialValue */
997     { 0x31,     9 },
998     { 0xa4,     1 },
999     { 0x3400,   9 },
1000     { 0x6789,   2 },
1001     { 0x9000,   9 },
1002     { 0xa000,   4 },
1003     { 0xabcd,   9 },
1004     { 0xbcde,   3 },
1005     { 0xcccc,   9 },
1006     { 0x110000, 6 }
1007 };
1008 
1009 /* empty or single-value tries, testing highStart==0 */
1010 static const SetRange
1011 setRangesEmpty[]={
1012     { 0,        0,        0, FALSE },  /* need some values for it to compile */
1013 };
1014 
1015 static const CheckRange
1016 checkRangesEmpty[]={
1017     { 0,        3 },
1018     { 0x110000, 3 }
1019 };
1020 
1021 static const SetRange
1022 setRangesSingleValue[]={
1023     { 0,        0x110000, 5, TRUE },
1024 };
1025 
1026 static const CheckRange
1027 checkRangesSingleValue[]={
1028     { 0,        3 },
1029     { 0x110000, 5 }
1030 };
1031 
1032 static void
TrieTest(void)1033 TrieTest(void) {
1034     testTrieRanges("set1", FALSE,
1035         setRanges1, UPRV_LENGTHOF(setRanges1),
1036         checkRanges1, UPRV_LENGTHOF(checkRanges1));
1037     testTrieRanges("set2-overlap", FALSE,
1038         setRanges2, UPRV_LENGTHOF(setRanges2),
1039         checkRanges2, UPRV_LENGTHOF(checkRanges2));
1040     testTrieRanges("set3-initial-9", FALSE,
1041         setRanges3, UPRV_LENGTHOF(setRanges3),
1042         checkRanges3, UPRV_LENGTHOF(checkRanges3));
1043     testTrieRanges("set-empty", FALSE,
1044         setRangesEmpty, 0,
1045         checkRangesEmpty, UPRV_LENGTHOF(checkRangesEmpty));
1046     testTrieRanges("set-single-value", FALSE,
1047         setRangesSingleValue, UPRV_LENGTHOF(setRangesSingleValue),
1048         checkRangesSingleValue, UPRV_LENGTHOF(checkRangesSingleValue));
1049 
1050     testTrieRanges("set2-overlap.withClone", TRUE,
1051         setRanges2, UPRV_LENGTHOF(setRanges2),
1052         checkRanges2, UPRV_LENGTHOF(checkRanges2));
1053 }
1054 
1055 static void
EnumNewTrieForLeadSurrogateTest(void)1056 EnumNewTrieForLeadSurrogateTest(void) {
1057     static const char *const testName="enum-for-lead";
1058     UTrie2 *trie=makeTrieWithRanges(testName, FALSE,
1059                                     setRanges2, UPRV_LENGTHOF(setRanges2),
1060                                     checkRanges2, UPRV_LENGTHOF(checkRanges2));
1061     while(trie!=NULL) {
1062         const CheckRange *checkRanges;
1063 
1064         checkRanges=checkRanges2_d800+1;
1065         utrie2_enumForLeadSurrogate(trie, 0xd800,
1066                                     testEnumValue, testEnumRange,
1067                                     &checkRanges);
1068         checkRanges=checkRanges2_d87e+1;
1069         utrie2_enumForLeadSurrogate(trie, 0xd87e,
1070                                     testEnumValue, testEnumRange,
1071                                     &checkRanges);
1072         checkRanges=checkRanges2_d87f+1;
1073         utrie2_enumForLeadSurrogate(trie, 0xd87f,
1074                                     testEnumValue, testEnumRange,
1075                                     &checkRanges);
1076         checkRanges=checkRanges2_dbff+1;
1077         utrie2_enumForLeadSurrogate(trie, 0xdbff,
1078                                     testEnumValue, testEnumRange,
1079                                     &checkRanges);
1080         if(!utrie2_isFrozen(trie)) {
1081             UErrorCode errorCode=U_ZERO_ERROR;
1082             utrie2_freeze(trie, UTRIE2_16_VALUE_BITS, &errorCode);
1083             if(U_FAILURE(errorCode)) {
1084                 log_err("error: utrie2_freeze(%s) failed\n", testName);
1085                 utrie2_close(trie);
1086                 return;
1087             }
1088         } else {
1089             utrie2_close(trie);
1090             break;
1091         }
1092     }
1093 }
1094 
1095 /* test utrie2_openDummy() -------------------------------------------------- */
1096 
1097 static void
dummyTest(UTrie2ValueBits valueBits)1098 dummyTest(UTrie2ValueBits valueBits) {
1099     CheckRange
1100     checkRanges[]={
1101         { -1,       0 },
1102         { 0,        0 },
1103         { 0x110000, 0 }
1104     };
1105 
1106     UTrie2 *trie;
1107     UErrorCode errorCode;
1108 
1109     const char *testName;
1110     uint32_t initialValue, errorValue;
1111 
1112     if(valueBits==UTRIE2_16_VALUE_BITS) {
1113         testName="dummy.16";
1114         initialValue=0x313;
1115         errorValue=0xaffe;
1116     } else {
1117         testName="dummy.32";
1118         initialValue=0x01234567;
1119         errorValue=0x89abcdef;
1120     }
1121     checkRanges[0].value=errorValue;
1122     checkRanges[1].value=checkRanges[2].value=initialValue;
1123 
1124     errorCode=U_ZERO_ERROR;
1125     trie=utrie2_openDummy(valueBits, initialValue, errorValue, &errorCode);
1126     if(U_FAILURE(errorCode)) {
1127         log_err("utrie2_openDummy(valueBits=%d) failed - %s\n", valueBits, u_errorName(errorCode));
1128         return;
1129     }
1130 
1131     testFrozenTrie(testName, trie, valueBits, checkRanges, UPRV_LENGTHOF(checkRanges));
1132     utrie2_close(trie);
1133 }
1134 
1135 static void
DummyTrieTest(void)1136 DummyTrieTest(void) {
1137     dummyTest(UTRIE2_16_VALUE_BITS);
1138     dummyTest(UTRIE2_32_VALUE_BITS);
1139 }
1140 
1141 /* test builder memory management ------------------------------------------- */
1142 
1143 static void
FreeBlocksTest(void)1144 FreeBlocksTest(void) {
1145     static const CheckRange
1146     checkRanges[]={
1147         { 0,        1 },
1148         { 0x740,    1 },
1149         { 0x780,    2 },
1150         { 0x880,    3 },
1151         { 0x110000, 1 }
1152     };
1153     static const char *const testName="free-blocks";
1154 
1155     UTrie2 *trie;
1156     int32_t i;
1157     UErrorCode errorCode;
1158 
1159     errorCode=U_ZERO_ERROR;
1160     trie=utrie2_open(1, 0xbad, &errorCode);
1161     if(U_FAILURE(errorCode)) {
1162         log_err("error: utrie2_open(%s) failed: %s\n", testName, u_errorName(errorCode));
1163         return;
1164     }
1165 
1166     /*
1167      * Repeatedly set overlapping same-value ranges to stress the free-data-block management.
1168      * If it fails, it will overflow the data array.
1169      */
1170     for(i=0; i<(0x120000>>UTRIE2_SHIFT_2)/2; ++i) {
1171         utrie2_setRange32(trie, 0x740, 0x840-1, 1, TRUE, &errorCode);
1172         utrie2_setRange32(trie, 0x780, 0x880-1, 1, TRUE, &errorCode);
1173         utrie2_setRange32(trie, 0x740, 0x840-1, 2, TRUE, &errorCode);
1174         utrie2_setRange32(trie, 0x780, 0x880-1, 3, TRUE, &errorCode);
1175     }
1176     /* make blocks that will be free during compaction */
1177     utrie2_setRange32(trie, 0x1000, 0x3000-1, 2, TRUE, &errorCode);
1178     utrie2_setRange32(trie, 0x2000, 0x4000-1, 3, TRUE, &errorCode);
1179     utrie2_setRange32(trie, 0x1000, 0x4000-1, 1, TRUE, &errorCode);
1180     /* set some values for lead surrogate code units */
1181     utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xd800, 90, &errorCode);
1182     utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xd999, 94, &errorCode);
1183     utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xdbff, 99, &errorCode);
1184     if(U_FAILURE(errorCode)) {
1185         log_err("error: setting lots of ranges into a trie (%s) failed - %s\n",
1186                 testName, u_errorName(errorCode));
1187         utrie2_close(trie);
1188         return;
1189     }
1190 
1191     trie=testTrieSerializeAllValueBits(testName, trie, FALSE,
1192                                        checkRanges, UPRV_LENGTHOF(checkRanges));
1193     utrie2_close(trie);
1194 }
1195 
1196 static void
GrowDataArrayTest(void)1197 GrowDataArrayTest(void) {
1198     static const CheckRange
1199     checkRanges[]={
1200         { 0,        1 },
1201         { 0x720,    2 },
1202         { 0x7a0,    3 },
1203         { 0x8a0,    4 },
1204         { 0x110000, 5 }
1205     };
1206     static const char *const testName="grow-data";
1207 
1208     UTrie2 *trie;
1209     int32_t i;
1210     UErrorCode errorCode;
1211 
1212     errorCode=U_ZERO_ERROR;
1213     trie=utrie2_open(1, 0xbad, &errorCode);
1214     if(U_FAILURE(errorCode)) {
1215         log_err("error: utrie2_open(%s) failed: %s\n", testName, u_errorName(errorCode));
1216         return;
1217     }
1218 
1219     /*
1220      * Use utrie2_set32() not utrie2_setRange32() to write non-initialValue-data.
1221      * Should grow/reallocate the data array to a sufficient length.
1222      */
1223     for(i=0; i<0x1000; ++i) {
1224         utrie2_set32(trie, i, 2, &errorCode);
1225     }
1226     for(i=0x720; i<0x1100; ++i) { /* some overlap */
1227         utrie2_set32(trie, i, 3, &errorCode);
1228     }
1229     for(i=0x7a0; i<0x900; ++i) {
1230         utrie2_set32(trie, i, 4, &errorCode);
1231     }
1232     for(i=0x8a0; i<0x110000; ++i) {
1233         utrie2_set32(trie, i, 5, &errorCode);
1234     }
1235     for(i=0xd800; i<0xdc00; ++i) {
1236         utrie2_set32ForLeadSurrogateCodeUnit(trie, i, 1, &errorCode);
1237     }
1238     /* set some values for lead surrogate code units */
1239     utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xd800, 90, &errorCode);
1240     utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xd999, 94, &errorCode);
1241     utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xdbff, 99, &errorCode);
1242     if(U_FAILURE(errorCode)) {
1243         log_err("error: setting lots of values into a trie (%s) failed - %s\n",
1244                 testName, u_errorName(errorCode));
1245         utrie2_close(trie);
1246         return;
1247     }
1248 
1249     trie=testTrieSerializeAllValueBits(testName, trie, FALSE,
1250                                           checkRanges, UPRV_LENGTHOF(checkRanges));
1251     utrie2_close(trie);
1252 }
1253 
1254 /* versions 1 and 2 --------------------------------------------------------- */
1255 
1256 static void
GetVersionTest(void)1257 GetVersionTest(void) {
1258     uint32_t data[4];
1259     if( /* version 1 */
1260         (data[0]=0x54726965, 1!=utrie2_getVersion(data, sizeof(data), FALSE)) ||
1261         (data[0]=0x54726965, 1!=utrie2_getVersion(data, sizeof(data), TRUE)) ||
1262         (data[0]=0x65697254, 0!=utrie2_getVersion(data, sizeof(data), FALSE)) ||
1263         (data[0]=0x65697254, 1!=utrie2_getVersion(data, sizeof(data), TRUE)) ||
1264         /* version 2 */
1265         (data[0]=0x54726932, 2!=utrie2_getVersion(data, sizeof(data), FALSE)) ||
1266         (data[0]=0x54726932, 2!=utrie2_getVersion(data, sizeof(data), TRUE)) ||
1267         (data[0]=0x32697254, 0!=utrie2_getVersion(data, sizeof(data), FALSE)) ||
1268         (data[0]=0x32697254, 2!=utrie2_getVersion(data, sizeof(data), TRUE)) ||
1269         /* illegal arguments */
1270         (data[0]=0x54726932, 0!=utrie2_getVersion(NULL, sizeof(data), FALSE)) ||
1271         (data[0]=0x54726932, 0!=utrie2_getVersion(data, 3, FALSE)) ||
1272         (data[0]=0x54726932, 0!=utrie2_getVersion((char *)data+1, sizeof(data), FALSE)) ||
1273         /* unknown signature values */
1274         (data[0]=0x11223344, 0!=utrie2_getVersion(data, sizeof(data), FALSE)) ||
1275         (data[0]=0x54726933, 0!=utrie2_getVersion(data, sizeof(data), FALSE))
1276     ) {
1277         log_err("error: utrie2_getVersion() is not working as expected\n");
1278     }
1279 }
1280 
1281 static UNewTrie *
makeNewTrie1WithRanges(const char * testName,const SetRange setRanges[],int32_t countSetRanges,const CheckRange checkRanges[],int32_t countCheckRanges)1282 makeNewTrie1WithRanges(const char *testName,
1283                        const SetRange setRanges[], int32_t countSetRanges,
1284                        const CheckRange checkRanges[], int32_t countCheckRanges) {
1285     UNewTrie *newTrie;
1286     uint32_t initialValue, errorValue;
1287     uint32_t value;
1288     UChar32 start, limit;
1289     int32_t i;
1290     UErrorCode errorCode;
1291     UBool overwrite, ok;
1292 
1293     log_verbose("\ntesting Trie '%s'\n", testName);
1294     errorCode=U_ZERO_ERROR;
1295     getSpecialValues(checkRanges, countCheckRanges, &initialValue, &errorValue);
1296     newTrie=utrie_open(NULL, NULL, 2000,
1297                        initialValue, initialValue,
1298                        FALSE);
1299     if(U_FAILURE(errorCode)) {
1300         log_err("error: utrie_open(%s) failed: %s\n", testName, u_errorName(errorCode));
1301         return NULL;
1302     }
1303 
1304     /* set values from setRanges[] */
1305     ok=TRUE;
1306     for(i=0; i<countSetRanges; ++i) {
1307         start=setRanges[i].start;
1308         limit=setRanges[i].limit;
1309         value=setRanges[i].value;
1310         overwrite=setRanges[i].overwrite;
1311         if((limit-start)==1 && overwrite) {
1312             ok&=utrie_set32(newTrie, start, value);
1313         } else {
1314             ok&=utrie_setRange32(newTrie, start, limit, value, overwrite);
1315         }
1316     }
1317     if(ok) {
1318         return newTrie;
1319     } else {
1320         log_err("error: setting values into a trie1 (%s) failed\n", testName);
1321         utrie_close(newTrie);
1322         return NULL;
1323     }
1324 }
1325 
1326 static void
testTrie2FromTrie1(const char * testName,const SetRange setRanges[],int32_t countSetRanges,const CheckRange checkRanges[],int32_t countCheckRanges)1327 testTrie2FromTrie1(const char *testName,
1328                    const SetRange setRanges[], int32_t countSetRanges,
1329                    const CheckRange checkRanges[], int32_t countCheckRanges) {
1330     uint32_t memory1_16[3000], memory1_32[3000];
1331     int32_t length16, length32;
1332     UChar lead;
1333 
1334     char name[40];
1335 
1336     UNewTrie *newTrie1_16, *newTrie1_32;
1337     UTrie trie1_16, trie1_32;
1338     UTrie2 *trie2;
1339     uint32_t initialValue, errorValue;
1340     UErrorCode errorCode;
1341 
1342     newTrie1_16=makeNewTrie1WithRanges(testName,
1343                                        setRanges, countSetRanges,
1344                                        checkRanges, countCheckRanges);
1345     if(newTrie1_16==NULL) {
1346         return;
1347     }
1348     newTrie1_32=utrie_clone(NULL, newTrie1_16, NULL, 0);
1349     if(newTrie1_32==NULL) {
1350         utrie_close(newTrie1_16);
1351         return;
1352     }
1353     errorCode=U_ZERO_ERROR;
1354     length16=utrie_serialize(newTrie1_16, memory1_16, sizeof(memory1_16),
1355                              NULL, TRUE, &errorCode);
1356     length32=utrie_serialize(newTrie1_32, memory1_32, sizeof(memory1_32),
1357                              NULL, FALSE, &errorCode);
1358     utrie_unserialize(&trie1_16, memory1_16, length16, &errorCode);
1359     utrie_unserialize(&trie1_32, memory1_32, length32, &errorCode);
1360     utrie_close(newTrie1_16);
1361     utrie_close(newTrie1_32);
1362     if(U_FAILURE(errorCode)) {
1363         log_err("error: utrie_serialize or unserialize(%s) failed: %s\n",
1364                 testName, u_errorName(errorCode));
1365         return;
1366     }
1367 
1368     getSpecialValues(checkRanges, countCheckRanges, &initialValue, &errorValue);
1369 
1370     uprv_strcpy(name, testName);
1371     uprv_strcat(name, ".16");
1372     trie2=utrie2_fromUTrie(&trie1_16, errorValue, &errorCode);
1373     if(U_SUCCESS(errorCode)) {
1374         testFrozenTrie(name, trie2, UTRIE2_16_VALUE_BITS, checkRanges, countCheckRanges);
1375         for(lead=0xd800; lead<0xdc00; ++lead) {
1376             uint32_t value1, value2;
1377             value1=UTRIE_GET16_FROM_LEAD(&trie1_16, lead);
1378             value2=UTRIE2_GET16_FROM_U16_SINGLE_LEAD(trie2, lead);
1379             if(value1!=value2) {
1380                 log_err("error: utrie2_fromUTrie(%s) wrong value %ld!=%ld "
1381                         "from lead surrogate code unit U+%04lx\n",
1382                         name, (long)value2, (long)value1, (long)lead);
1383                 break;
1384             }
1385         }
1386     }
1387     utrie2_close(trie2);
1388 
1389     uprv_strcpy(name, testName);
1390     uprv_strcat(name, ".32");
1391     trie2=utrie2_fromUTrie(&trie1_32, errorValue, &errorCode);
1392     if(U_SUCCESS(errorCode)) {
1393         testFrozenTrie(name, trie2, UTRIE2_32_VALUE_BITS, checkRanges, countCheckRanges);
1394         for(lead=0xd800; lead<0xdc00; ++lead) {
1395             uint32_t value1, value2;
1396             value1=UTRIE_GET32_FROM_LEAD(&trie1_32, lead);
1397             value2=UTRIE2_GET32_FROM_U16_SINGLE_LEAD(trie2, lead);
1398             if(value1!=value2) {
1399                 log_err("error: utrie2_fromUTrie(%s) wrong value %ld!=%ld "
1400                         "from lead surrogate code unit U+%04lx\n",
1401                         name, (long)value2, (long)value1, (long)lead);
1402                 break;
1403             }
1404         }
1405     }
1406     utrie2_close(trie2);
1407 }
1408 
1409 static void
Trie12ConversionTest(void)1410 Trie12ConversionTest(void) {
1411     testTrie2FromTrie1("trie1->trie2",
1412                        setRanges2, UPRV_LENGTHOF(setRanges2),
1413                        checkRanges2, UPRV_LENGTHOF(checkRanges2));
1414 }
1415 
1416 void
addTrie2Test(TestNode ** root)1417 addTrie2Test(TestNode** root) {
1418     addTest(root, &TrieTest, "tsutil/trie2test/TrieTest");
1419     addTest(root, &EnumNewTrieForLeadSurrogateTest,
1420                   "tsutil/trie2test/EnumNewTrieForLeadSurrogateTest");
1421     addTest(root, &DummyTrieTest, "tsutil/trie2test/DummyTrieTest");
1422     addTest(root, &FreeBlocksTest, "tsutil/trie2test/FreeBlocksTest");
1423     addTest(root, &GrowDataArrayTest, "tsutil/trie2test/GrowDataArrayTest");
1424     addTest(root, &GetVersionTest, "tsutil/trie2test/GetVersionTest");
1425     addTest(root, &Trie12ConversionTest, "tsutil/trie2test/Trie12ConversionTest");
1426 }
1427