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