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