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