• 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-2016, 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: 2001nov20
16 *   created by: Markus W. Scherer
17 */
18 
19 #include <stdbool.h>
20 #include <stdio.h>
21 #include "unicode/utypes.h"
22 #include "unicode/utf16.h"
23 #include "utrie.h"
24 #include "cstring.h"
25 #include "cmemory.h"
26 
27 #if 1
28 #include "cintltst.h"
29 #else
30 /* definitions from standalone utrie development */
31 #define log_err printf
32 #define log_verbose printf
33 
34 #undef u_errorName
35 #define u_errorName(errorCode) "some error code"
36 #endif
37 
38 /* Values for setting possibly overlapping, out-of-order ranges of values */
39 typedef struct SetRange {
40     UChar32 start, limit;
41     uint32_t value;
42     UBool overwrite;
43 } SetRange;
44 
45 /*
46  * Values for testing:
47  * value is set from the previous boundary's limit to before
48  * this boundary's limit
49  */
50 typedef struct CheckRange {
51     UChar32 limit;
52     uint32_t value;
53 } CheckRange;
54 
55 
56 static uint32_t U_CALLCONV
_testFoldedValue32(UNewTrie * trie,UChar32 start,int32_t offset)57 _testFoldedValue32(UNewTrie *trie, UChar32 start, int32_t offset) {
58     uint32_t foldedValue, value;
59     UChar32 limit;
60     UBool inBlockZero;
61 
62     foldedValue=0;
63 
64     limit=start+0x400;
65     while(start<limit) {
66         value=utrie_get32(trie, start, &inBlockZero);
67         if(inBlockZero) {
68             start+=UTRIE_DATA_BLOCK_LENGTH;
69         } else {
70             foldedValue|=value;
71             ++start;
72         }
73     }
74 
75     if(foldedValue!=0) {
76         return ((uint32_t)offset<<16)|foldedValue;
77     } else {
78         return 0;
79     }
80 }
81 
82 static int32_t U_CALLCONV
_testFoldingOffset32(uint32_t data)83 _testFoldingOffset32(uint32_t data) {
84     return (int32_t)(data>>16);
85 }
86 
87 static uint32_t U_CALLCONV
_testFoldedValue16(UNewTrie * trie,UChar32 start,int32_t offset)88 _testFoldedValue16(UNewTrie *trie, UChar32 start, int32_t offset) {
89     uint32_t foldedValue, value;
90     UChar32 limit;
91     UBool inBlockZero;
92 
93     foldedValue=0;
94 
95     limit=start+0x400;
96     while(start<limit) {
97         value=utrie_get32(trie, start, &inBlockZero);
98         if(inBlockZero) {
99             start+=UTRIE_DATA_BLOCK_LENGTH;
100         } else {
101             foldedValue|=value;
102             ++start;
103         }
104     }
105 
106     if(foldedValue!=0) {
107         return (uint32_t)(offset|0x8000);
108     } else {
109         return 0;
110     }
111 }
112 
113 static int32_t U_CALLCONV
_testFoldingOffset16(uint32_t data)114 _testFoldingOffset16(uint32_t data) {
115     if(data&0x8000) {
116         return (int32_t)(data&0x7fff);
117     } else {
118         return 0;
119     }
120 }
121 
122 static uint32_t U_CALLCONV
_testEnumValue(const void * context,uint32_t value)123 _testEnumValue(const void *context, uint32_t value) {
124     (void)context; // suppress compiler warnings about unused variable
125     return value^0x5555;
126 }
127 
128 static UBool U_CALLCONV
_testEnumRange(const void * context,UChar32 start,UChar32 limit,uint32_t value)129 _testEnumRange(const void *context, UChar32 start, UChar32 limit, uint32_t value) {
130     const CheckRange **pb=(const CheckRange **)context;
131     const CheckRange *b=(*pb)++;
132 
133     value^=0x5555;
134     if(start!=(b-1)->limit || limit!=b->limit || value!=b->value) {
135         log_err("error: utrie_enum() delivers wrong range [U+%04lx..U+%04lx[.0x%lx instead of [U+%04lx..U+%04lx[.0x%lx\n",
136             start, limit, value,
137             (b-1)->limit, b->limit, b->value);
138     }
139     return true;
140 }
141 
142 static void
testTrieIteration(const char * testName,const UTrie * trie,const CheckRange checkRanges[],int32_t countCheckRanges)143 testTrieIteration(const char *testName,
144                   const UTrie *trie,
145                   const CheckRange checkRanges[], int32_t countCheckRanges) {
146     UChar s[100];
147     uint32_t values[30];
148 
149     const UChar *p, *limit;
150 
151     uint32_t value;
152     UChar32 c;
153     int32_t i, length, countValues;
154     UChar c2;
155 
156     /* write a string */
157     length=countValues=0;
158     for(i=0; i<countCheckRanges; ++i) {
159         c=checkRanges[i].limit;
160         if(c!=0) {
161             --c;
162             U16_APPEND_UNSAFE(s, length, c);
163             values[countValues++]=checkRanges[i].value;
164         }
165     }
166     limit=s+length;
167 
168     /* try forward */
169     p=s;
170     i=0;
171     while(p<limit) {
172         c=c2=0x33;
173         if(trie->data32!=NULL) {
174             UTRIE_NEXT32(trie, p, limit, c, c2, value);
175         } else {
176             UTRIE_NEXT16(trie, p, limit, c, c2, value);
177         }
178         if(value!=values[i]) {
179             log_err("error: wrong value from UTRIE_NEXT(%s)(U+%04lx, U+%04lx): 0x%lx instead of 0x%lx\n",
180                     testName, c, c2, value, values[i]);
181         }
182         if(
183             c2==0 ?
184                 c!=*(p-1) :
185                 !U16_IS_LEAD(c) || !U16_IS_TRAIL(c2) || c!=*(p-2) || c2!=*(p-1)
186         ) {
187             log_err("error: wrong (c, c2) from UTRIE_NEXT(%s): (U+%04lx, U+%04lx)\n",
188                     testName, c, c2);
189             continue;
190         }
191         if(c2!=0) {
192             int32_t offset;
193 
194             if(trie->data32==NULL) {
195                 value=UTRIE_GET16_FROM_LEAD(trie, c);
196                 offset=trie->getFoldingOffset(value);
197                 if(offset>0) {
198                     value=UTRIE_GET16_FROM_OFFSET_TRAIL(trie, offset, c2);
199                 } else {
200                     value=trie->initialValue;
201                 }
202             } else {
203                 value=UTRIE_GET32_FROM_LEAD(trie, c);
204                 offset=trie->getFoldingOffset(value);
205                 if(offset>0) {
206                     value=UTRIE_GET32_FROM_OFFSET_TRAIL(trie, offset, c2);
207                 } else {
208                     value=trie->initialValue;
209                 }
210             }
211             if(value!=values[i]) {
212                 log_err("error: wrong value from UTRIE_GETXX_FROM_OFFSET_TRAIL(%s)(U+%04lx, U+%04lx): 0x%lx instead of 0x%lx\n",
213                         testName, c, c2, value, values[i]);
214             }
215         }
216         if(c2!=0) {
217             value=0x44;
218             if(trie->data32==NULL) {
219                 UTRIE_GET16_FROM_PAIR(trie, c, c2, value);
220             } else {
221                 UTRIE_GET32_FROM_PAIR(trie, c, c2, value);
222             }
223             if(value!=values[i]) {
224                 log_err("error: wrong value from UTRIE_GETXX_FROM_PAIR(%s)(U+%04lx, U+%04lx): 0x%lx instead of 0x%lx\n",
225                         testName, c, c2, value, values[i]);
226             }
227         }
228         ++i;
229     }
230 
231     /* try backward */
232     p=limit;
233     i=countValues;
234     while(s<p) {
235         --i;
236         c=c2=0x33;
237         if(trie->data32!=NULL) {
238             UTRIE_PREVIOUS32(trie, s, p, c, c2, value);
239         } else {
240             UTRIE_PREVIOUS16(trie, s, p, c, c2, value);
241         }
242         if(value!=values[i]) {
243             log_err("error: wrong value from UTRIE_PREVIOUS(%s)(U+%04lx, U+%04lx): 0x%lx instead of 0x%lx\n",
244                     testName, c, c2, value, values[i]);
245         }
246         if(
247             c2==0 ?
248                 c!=*p:
249                 !U16_IS_LEAD(c) || !U16_IS_TRAIL(c2) || c!=*p || c2!=*(p+1)
250         ) {
251             log_err("error: wrong (c, c2) from UTRIE_PREVIOUS(%s): (U+%04lx, U+%04lx)\n",
252                     testName, c, c2);
253         }
254     }
255 }
256 
257 static void
testTrieRangesWithMalloc(const char * testName,const SetRange setRanges[],int32_t countSetRanges,const CheckRange checkRanges[],int32_t countCheckRanges,UBool dataIs32,UBool latin1Linear)258 testTrieRangesWithMalloc(const char *testName,
259                const SetRange setRanges[], int32_t countSetRanges,
260                const CheckRange checkRanges[], int32_t countCheckRanges,
261                UBool dataIs32, UBool latin1Linear) {
262     UTrieGetFoldingOffset *getFoldingOffset;
263     const CheckRange *enumRanges;
264     UNewTrie *newTrie;
265     UTrie trie={ 0 };
266     uint32_t value, value2;
267     UChar32 start, limit;
268     int32_t i, length;
269     UErrorCode errorCode;
270     UBool overwrite, ok;
271     uint8_t* storage =NULL;
272     static const int32_t DEFAULT_STORAGE_SIZE = 32768;
273     storage = (uint8_t*) uprv_malloc(sizeof(uint8_t)*DEFAULT_STORAGE_SIZE);
274 
275     log_verbose("\ntesting Trie '%s'\n", testName);
276     newTrie=utrie_open(NULL, NULL, 2000,
277                        checkRanges[0].value, checkRanges[0].value,
278                        latin1Linear);
279 
280     /* set values from setRanges[] */
281     ok=true;
282     for(i=0; i<countSetRanges; ++i) {
283         start=setRanges[i].start;
284         limit=setRanges[i].limit;
285         value=setRanges[i].value;
286         overwrite=setRanges[i].overwrite;
287         if((limit-start)==1 && overwrite) {
288             ok&=utrie_set32(newTrie, start, value);
289         } else {
290             ok&=utrie_setRange32(newTrie, start, limit, value, overwrite);
291         }
292     }
293     if(!ok) {
294         log_err("error: setting values into a trie failed (%s)\n", testName);
295         return;
296     }
297 
298     /* verify that all these values are in the new Trie */
299     start=0;
300     for(i=0; i<countCheckRanges; ++i) {
301         limit=checkRanges[i].limit;
302         value=checkRanges[i].value;
303 
304         while(start<limit) {
305             if(value!=utrie_get32(newTrie, start, NULL)) {
306                 log_err("error: newTrie(%s)[U+%04lx]==0x%lx instead of 0x%lx\n",
307                         testName, start, utrie_get32(newTrie, start, NULL), value);
308             }
309             ++start;
310         }
311     }
312 
313     if(dataIs32) {
314         getFoldingOffset=_testFoldingOffset32;
315     } else {
316         getFoldingOffset=_testFoldingOffset16;
317     }
318 
319     errorCode=U_ZERO_ERROR;
320     length=utrie_serialize(newTrie, storage, DEFAULT_STORAGE_SIZE,
321                            dataIs32 ? _testFoldedValue32 : _testFoldedValue16,
322                            (UBool)!dataIs32,
323                            &errorCode);
324     if(U_FAILURE(errorCode)) {
325         log_err("error: utrie_serialize(%s) failed: %s\n", testName, u_errorName(errorCode));
326         utrie_close(newTrie);
327         return;
328     }
329 
330     /* test linear Latin-1 range from utrie_getData() */
331     if(latin1Linear) {
332         uint32_t *data;
333         int32_t dataLength;
334 
335         data=utrie_getData(newTrie, &dataLength);
336         start=0;
337         for(i=0; i<countCheckRanges && start<=0xff; ++i) {
338             limit=checkRanges[i].limit;
339             value=checkRanges[i].value;
340 
341             while(start<limit && start<=0xff) {
342                 if(value!=data[UTRIE_DATA_BLOCK_LENGTH+start]) {
343                     log_err("error: newTrie(%s).latin1Data[U+%04lx]==0x%lx instead of 0x%lx\n",
344                             testName, start, data[UTRIE_DATA_BLOCK_LENGTH+start], value);
345                 }
346                 ++start;
347             }
348         }
349     }
350 
351     utrie_close(newTrie);
352 
353     errorCode=U_ZERO_ERROR;
354     if(!utrie_unserialize(&trie, storage, length, &errorCode)) {
355         log_err("error: utrie_unserialize() failed, %s\n", u_errorName(errorCode));
356         return;
357     }
358     trie.getFoldingOffset=getFoldingOffset;
359 
360     if(dataIs32!=(trie.data32!=NULL)) {
361         log_err("error: trie serialization (%s) did not preserve 32-bitness\n", testName);
362     }
363     if(latin1Linear!=trie.isLatin1Linear) {
364         log_err("error: trie serialization (%s) did not preserve Latin-1-linearity\n", testName);
365     }
366 
367     /* verify that all these values are in the unserialized Trie */
368     start=0;
369     for(i=0; i<countCheckRanges; ++i) {
370         limit=checkRanges[i].limit;
371         value=checkRanges[i].value;
372 
373         if(start==0xd800) {
374             /* skip surrogates */
375             start=limit;
376             continue;
377         }
378 
379         while(start<limit) {
380             if(start<=0xffff) {
381                 if(dataIs32) {
382                     value2=UTRIE_GET32_FROM_BMP(&trie, start);
383                 } else {
384                     value2=UTRIE_GET16_FROM_BMP(&trie, start);
385                 }
386                 if(value!=value2) {
387                     log_err("error: unserialized trie(%s).fromBMP(U+%04lx)==0x%lx instead of 0x%lx\n",
388                             testName, start, value2, value);
389                 }
390                 if(!U16_IS_LEAD(start)) {
391                     if(dataIs32) {
392                         value2=UTRIE_GET32_FROM_LEAD(&trie, start);
393                     } else {
394                         value2=UTRIE_GET16_FROM_LEAD(&trie, start);
395                     }
396                     if(value!=value2) {
397                         log_err("error: unserialized trie(%s).fromLead(U+%04lx)==0x%lx instead of 0x%lx\n",
398                                 testName, start, value2, value);
399                     }
400                 }
401             }
402             if(dataIs32) {
403                 UTRIE_GET32(&trie, start, value2);
404             } else {
405                 UTRIE_GET16(&trie, start, value2);
406             }
407             if(value!=value2) {
408                 log_err("error: unserialized trie(%s).get(U+%04lx)==0x%lx instead of 0x%lx\n",
409                         testName, start, value2, value);
410             }
411             ++start;
412         }
413     }
414 
415     /* enumerate and verify all ranges */
416     enumRanges=checkRanges+1;
417     utrie_enum(&trie, _testEnumValue, _testEnumRange, &enumRanges);
418 
419     /* test linear Latin-1 range */
420     if(trie.isLatin1Linear) {
421         if(trie.data32!=NULL) {
422             const uint32_t *latin1=UTRIE_GET32_LATIN1(&trie);
423 
424             for(start=0; start<0x100; ++start) {
425                 if(latin1[start]!=UTRIE_GET32_FROM_LEAD(&trie, start)) {
426                     log_err("error: (%s) trie.latin1[U+%04lx]=0x%lx!=0x%lx=trie.get32(U+%04lx)\n",
427                             testName, start, latin1[start], UTRIE_GET32_FROM_LEAD(&trie, start), start);
428                 }
429             }
430         } else {
431             const uint16_t *latin1=UTRIE_GET16_LATIN1(&trie);
432 
433             for(start=0; start<0x100; ++start) {
434                 if(latin1[start]!=UTRIE_GET16_FROM_LEAD(&trie, start)) {
435                     log_err("error: (%s) trie.latin1[U+%04lx]=0x%lx!=0x%lx=trie.get16(U+%04lx)\n",
436                             testName, start, latin1[start], UTRIE_GET16_FROM_LEAD(&trie, start), start);
437                 }
438             }
439         }
440     }
441 
442     testTrieIteration(testName, &trie, checkRanges, countCheckRanges);
443     uprv_free(storage);
444 }
445 
446 static void
testTrieRanges(const char * testName,const SetRange setRanges[],int32_t countSetRanges,const CheckRange checkRanges[],int32_t countCheckRanges,UBool dataIs32,UBool latin1Linear)447 testTrieRanges(const char *testName,
448                const SetRange setRanges[], int32_t countSetRanges,
449                const CheckRange checkRanges[], int32_t countCheckRanges,
450                UBool dataIs32, UBool latin1Linear) {
451     union{
452         double bogus; /* needed for aligning the storage */
453         uint8_t storage[32768];
454     } storageHolder;
455     UTrieGetFoldingOffset *getFoldingOffset;
456     UNewTrieGetFoldedValue *getFoldedValue;
457     const CheckRange *enumRanges;
458     UNewTrie *newTrie;
459     UTrie trie={ 0 };
460     uint32_t value, value2;
461     UChar32 start, limit;
462     int32_t i, length;
463     UErrorCode errorCode;
464     UBool overwrite, ok;
465 
466     log_verbose("\ntesting Trie '%s'\n", testName);
467     newTrie=utrie_open(NULL, NULL, 2000,
468                        checkRanges[0].value, checkRanges[0].value,
469                        latin1Linear);
470 
471     /* set values from setRanges[] */
472     ok=true;
473     for(i=0; i<countSetRanges; ++i) {
474         start=setRanges[i].start;
475         limit=setRanges[i].limit;
476         value=setRanges[i].value;
477         overwrite=setRanges[i].overwrite;
478         if((limit-start)==1 && overwrite) {
479             ok&=utrie_set32(newTrie, start, value);
480         } else {
481             ok&=utrie_setRange32(newTrie, start, limit, value, overwrite);
482         }
483     }
484     if(!ok) {
485         log_err("error: setting values into a trie failed (%s)\n", testName);
486         return;
487     }
488 
489     /* verify that all these values are in the new Trie */
490     start=0;
491     for(i=0; i<countCheckRanges; ++i) {
492         limit=checkRanges[i].limit;
493         value=checkRanges[i].value;
494 
495         while(start<limit) {
496             if(value!=utrie_get32(newTrie, start, NULL)) {
497                 log_err("error: newTrie(%s)[U+%04lx]==0x%lx instead of 0x%lx\n",
498                         testName, start, utrie_get32(newTrie, start, NULL), value);
499             }
500             ++start;
501         }
502     }
503 
504     if(dataIs32) {
505         getFoldingOffset=_testFoldingOffset32;
506         getFoldedValue=_testFoldedValue32;
507     } else {
508         getFoldingOffset=_testFoldingOffset16;
509         getFoldedValue=_testFoldedValue16;
510     }
511 
512     /*
513      * code coverage for utrie.c/defaultGetFoldedValue(),
514      * pick some combination of parameters for selecting the UTrie defaults
515      */
516     if(!dataIs32 && latin1Linear) {
517         getFoldingOffset=NULL;
518         getFoldedValue=NULL;
519     }
520 
521     errorCode=U_ZERO_ERROR;
522     length=utrie_serialize(newTrie, storageHolder.storage, sizeof(storageHolder.storage),
523                            getFoldedValue,
524                            (UBool)!dataIs32,
525                            &errorCode);
526     if(U_FAILURE(errorCode)) {
527         log_err("error: utrie_serialize(%s) failed: %s\n", testName, u_errorName(errorCode));
528         utrie_close(newTrie);
529         return;
530     }
531     if (length >= (int32_t)sizeof(storageHolder.storage)) {
532         log_err("error: utrie_serialize(%s) needs more memory\n", testName);
533         utrie_close(newTrie);
534         return;
535     }
536 
537     /* test linear Latin-1 range from utrie_getData() */
538     if(latin1Linear) {
539         uint32_t *data;
540         int32_t dataLength;
541 
542         data=utrie_getData(newTrie, &dataLength);
543         start=0;
544         for(i=0; i<countCheckRanges && start<=0xff; ++i) {
545             limit=checkRanges[i].limit;
546             value=checkRanges[i].value;
547 
548             while(start<limit && start<=0xff) {
549                 if(value!=data[UTRIE_DATA_BLOCK_LENGTH+start]) {
550                     log_err("error: newTrie(%s).latin1Data[U+%04lx]==0x%lx instead of 0x%lx\n",
551                             testName, start, data[UTRIE_DATA_BLOCK_LENGTH+start], value);
552                 }
553                 ++start;
554             }
555         }
556     }
557 
558     utrie_close(newTrie);
559 
560     errorCode=U_ZERO_ERROR;
561     if(!utrie_unserialize(&trie, storageHolder.storage, length, &errorCode)) {
562         log_err("error: utrie_unserialize() failed, %s\n", u_errorName(errorCode));
563         return;
564     }
565     if(getFoldingOffset!=NULL) {
566         trie.getFoldingOffset=getFoldingOffset;
567     }
568 
569     if(dataIs32!=(trie.data32!=NULL)) {
570         log_err("error: trie serialization (%s) did not preserve 32-bitness\n", testName);
571     }
572     if(latin1Linear!=trie.isLatin1Linear) {
573         log_err("error: trie serialization (%s) did not preserve Latin-1-linearity\n", testName);
574     }
575 
576     /* verify that all these values are in the unserialized Trie */
577     start=0;
578     for(i=0; i<countCheckRanges; ++i) {
579         limit=checkRanges[i].limit;
580         value=checkRanges[i].value;
581 
582         if(start==0xd800) {
583             /* skip surrogates */
584             start=limit;
585             continue;
586         }
587 
588         while(start<limit) {
589             if(start<=0xffff) {
590                 if(dataIs32) {
591                     value2=UTRIE_GET32_FROM_BMP(&trie, start);
592                 } else {
593                     value2=UTRIE_GET16_FROM_BMP(&trie, start);
594                 }
595                 if(value!=value2) {
596                     log_err("error: unserialized trie(%s).fromBMP(U+%04lx)==0x%lx instead of 0x%lx\n",
597                             testName, start, value2, value);
598                 }
599                 if(!U16_IS_LEAD(start)) {
600                     if(dataIs32) {
601                         value2=UTRIE_GET32_FROM_LEAD(&trie, start);
602                     } else {
603                         value2=UTRIE_GET16_FROM_LEAD(&trie, start);
604                     }
605                     if(value!=value2) {
606                         log_err("error: unserialized trie(%s).fromLead(U+%04lx)==0x%lx instead of 0x%lx\n",
607                                 testName, start, value2, value);
608                     }
609                 }
610             }
611             if(dataIs32) {
612                 UTRIE_GET32(&trie, start, value2);
613             } else {
614                 UTRIE_GET16(&trie, start, value2);
615             }
616             if(value!=value2) {
617                 log_err("error: unserialized trie(%s).get(U+%04lx)==0x%lx instead of 0x%lx\n",
618                         testName, start, value2, value);
619             }
620             ++start;
621         }
622     }
623 
624     /* enumerate and verify all ranges */
625     enumRanges=checkRanges+1;
626     utrie_enum(&trie, _testEnumValue, _testEnumRange, &enumRanges);
627 
628     /* test linear Latin-1 range */
629     if(trie.isLatin1Linear) {
630         if(trie.data32!=NULL) {
631             const uint32_t *latin1=UTRIE_GET32_LATIN1(&trie);
632 
633             for(start=0; start<0x100; ++start) {
634                 if(latin1[start]!=UTRIE_GET32_FROM_LEAD(&trie, start)) {
635                     log_err("error: (%s) trie.latin1[U+%04lx]=0x%lx!=0x%lx=trie.get32(U+%04lx)\n",
636                             testName, start, latin1[start], UTRIE_GET32_FROM_LEAD(&trie, start), start);
637                 }
638             }
639         } else {
640             const uint16_t *latin1=UTRIE_GET16_LATIN1(&trie);
641 
642             for(start=0; start<0x100; ++start) {
643                 if(latin1[start]!=UTRIE_GET16_FROM_LEAD(&trie, start)) {
644                     log_err("error: (%s) trie.latin1[U+%04lx]=0x%lx!=0x%lx=trie.get16(U+%04lx)\n",
645                             testName, start, latin1[start], UTRIE_GET16_FROM_LEAD(&trie, start), start);
646                 }
647             }
648         }
649     }
650 
651     testTrieIteration(testName, &trie, checkRanges, countCheckRanges);
652 }
653 
654 static void
testTrieRanges2(const char * testName,const SetRange setRanges[],int32_t countSetRanges,const CheckRange checkRanges[],int32_t countCheckRanges,UBool dataIs32)655 testTrieRanges2(const char *testName,
656                 const SetRange setRanges[], int32_t countSetRanges,
657                 const CheckRange checkRanges[], int32_t countCheckRanges,
658                 UBool dataIs32) {
659     char name[40];
660 
661     testTrieRanges(testName,
662                    setRanges, countSetRanges,
663                    checkRanges, countCheckRanges,
664                    dataIs32, false);
665     testTrieRangesWithMalloc(testName,
666                    setRanges, countSetRanges,
667                    checkRanges, countCheckRanges,
668                    dataIs32, false);
669 
670     uprv_strcpy(name, testName);
671     uprv_strcat(name, "-latin1Linear");
672     testTrieRanges(name,
673                    setRanges, countSetRanges,
674                    checkRanges, countCheckRanges,
675                    dataIs32, true);
676     testTrieRangesWithMalloc(name,
677                    setRanges, countSetRanges,
678                    checkRanges, countCheckRanges,
679                    dataIs32, true);
680 }
681 
682 static void
testTrieRanges4(const char * testName,const SetRange setRanges[],int32_t countSetRanges,const CheckRange checkRanges[],int32_t countCheckRanges)683 testTrieRanges4(const char *testName,
684                 const SetRange setRanges[], int32_t countSetRanges,
685                 const CheckRange checkRanges[], int32_t countCheckRanges) {
686     char name[40];
687 
688     uprv_strcpy(name, testName);
689     uprv_strcat(name, ".32");
690     testTrieRanges2(name,
691                     setRanges, countSetRanges,
692                     checkRanges, countCheckRanges,
693                     true);
694 
695     uprv_strcpy(name, testName);
696     uprv_strcat(name, ".16");
697     testTrieRanges2(name,
698                     setRanges, countSetRanges,
699                     checkRanges, countCheckRanges,
700                     false);
701 }
702 
703 /* test data ----------------------------------------------------------------*/
704 
705 /* set consecutive ranges, even with value 0 */
706 static const SetRange
707 setRanges1[]={
708     {0,      0x20,       0,      false},
709     {0x20,   0xa7,       0x1234, false},
710     {0xa7,   0x3400,     0,      false},
711     {0x3400, 0x9fa6,     0x6162, false},
712     {0x9fa6, 0xda9e,     0x3132, false},
713     {0xdada, 0xeeee,     0x87ff, false}, /* try to disrupt _testFoldingOffset16() */
714     {0xeeee, 0x11111,    1,      false},
715     {0x11111, 0x44444,   0x6162, false},
716     {0x44444, 0x60003,   0,      false},
717     {0xf0003, 0xf0004,   0xf,    false},
718     {0xf0004, 0xf0006,   0x10,   false},
719     {0xf0006, 0xf0007,   0x11,   false},
720     {0xf0007, 0xf0020,   0x12,   false},
721     {0xf0020, 0x110000,  0,      false}
722 };
723 
724 static const CheckRange
725 checkRanges1[]={
726     {0,      0},      /* dummy start range to make _testEnumRange() simpler */
727     {0x20,   0},
728     {0xa7,   0x1234},
729     {0x3400, 0},
730     {0x9fa6, 0x6162},
731     {0xda9e, 0x3132},
732     {0xdada, 0},
733     {0xeeee, 0x87ff},
734     {0x11111,1},
735     {0x44444,0x6162},
736     {0xf0003,0},
737     {0xf0004,0xf},
738     {0xf0006,0x10},
739     {0xf0007,0x11},
740     {0xf0020,0x12},
741     {0x110000, 0}
742 };
743 
744 /* set some interesting overlapping ranges */
745 static const SetRange
746 setRanges2[]={
747     {0x21,   0x7f,       0x5555, true},
748     {0x2f800,0x2fedc,    0x7a,   true},
749     {0x72,   0xdd,       3,      true},
750     {0xdd,   0xde,       4,      false},
751     {0x201,  0x220,      6,      true},  /* 3 consecutive blocks with the same pattern but discontiguous value ranges */
752     {0x221,  0x240,      6,      true},
753     {0x241,  0x260,      6,      true},
754     {0x2f987,0x2fa98,    5,      true},
755     {0x2f777,0x2f833,    0,      true},
756     {0x2f900,0x2ffee,    1,      false},
757     {0x2ffee,0x2ffef,    2,      true}
758 };
759 
760 static const CheckRange
761 checkRanges2[]={
762     {0,      0},      /* dummy start range to make _testEnumRange() simpler */
763     {0x21,   0},
764     {0x72,   0x5555},
765     {0xdd,   3},
766     {0xde,   4},
767     {0x201,  0},
768     {0x220,  6},
769     {0x221,  0},
770     {0x240,  6},
771     {0x241,  0},
772     {0x260,  6},
773     {0x2f833,0},
774     {0x2f987,0x7a},
775     {0x2fa98,5},
776     {0x2fedc,0x7a},
777     {0x2ffee,1},
778     {0x2ffef,2},
779     {0x110000, 0}
780 };
781 
782 /* use a non-zero initial value */
783 static const SetRange
784 setRanges3[]={
785     {0x31,   0xa4,   1,  false},
786     {0x3400, 0x6789, 2,  false},
787     {0x30000,0x34567,9,  true},
788     {0x45678,0x56789,3,  true}
789 };
790 
791 static const CheckRange
792 checkRanges3[]={
793     {0,      9},      /* dummy start range, also carries the initial value */
794     {0x31,   9},
795     {0xa4,   1},
796     {0x3400, 9},
797     {0x6789, 2},
798     {0x45678,9},
799     {0x56789,3},
800     {0x110000,9}
801 };
802 
803 static void
TrieTest(void)804 TrieTest(void) {
805     testTrieRanges4("set1",
806         setRanges1, UPRV_LENGTHOF(setRanges1),
807         checkRanges1, UPRV_LENGTHOF(checkRanges1));
808     testTrieRanges4("set2-overlap",
809         setRanges2, UPRV_LENGTHOF(setRanges2),
810         checkRanges2, UPRV_LENGTHOF(checkRanges2));
811     testTrieRanges4("set3-initial-9",
812         setRanges3, UPRV_LENGTHOF(setRanges3),
813         checkRanges3, UPRV_LENGTHOF(checkRanges3));
814 }
815 
816 /* test utrie_unserializeDummy() -------------------------------------------- */
817 
818 static int32_t U_CALLCONV
dummyGetFoldingOffset(uint32_t data)819 dummyGetFoldingOffset(uint32_t data) {
820     (void)data; // suppress compiler warnings about unused variable
821     return -1; /* never get non-initialValue data for supplementary code points */
822 }
823 
824 static void
dummyTest(UBool make16BitTrie)825 dummyTest(UBool make16BitTrie) {
826     int32_t mem[UTRIE_DUMMY_SIZE/4];
827 
828     UTrie trie;
829     UErrorCode errorCode;
830     UChar32 c;
831 
832     uint32_t value, initialValue, leadUnitValue;
833 
834     if(make16BitTrie) {
835         initialValue=0x313;
836         leadUnitValue=0xaffe;
837     } else {
838         initialValue=0x01234567;
839         leadUnitValue=0x89abcdef;
840     }
841 
842     errorCode=U_ZERO_ERROR;
843     utrie_unserializeDummy(&trie, mem, sizeof(mem), initialValue, leadUnitValue, make16BitTrie, &errorCode);
844     if(U_FAILURE(errorCode)) {
845         log_err("utrie_unserializeDummy(make16BitTrie=%d) failed - %s\n", make16BitTrie, u_errorName(errorCode));
846         return;
847     }
848     trie.getFoldingOffset=dummyGetFoldingOffset;
849 
850     /* test that all code points have initialValue */
851     for(c=0; c<=0x10ffff; ++c) {
852         if(make16BitTrie) {
853             UTRIE_GET16(&trie, c, value);
854         } else {
855             UTRIE_GET32(&trie, c, value);
856         }
857         if(value!=initialValue) {
858             log_err("UTRIE_GET%s(dummy, U+%04lx)=0x%lx instead of 0x%lx\n",
859                 make16BitTrie ? "16" : "32", (long)c, (long)value, (long)initialValue);
860         }
861     }
862 
863     /* test that the lead surrogate code units have leadUnitValue */
864     for(c=0xd800; c<=0xdbff; ++c) {
865         if(make16BitTrie) {
866             value=UTRIE_GET16_FROM_LEAD(&trie, c);
867         } else {
868             value=UTRIE_GET32_FROM_LEAD(&trie, c);
869         }
870         if(value!=leadUnitValue) {
871             log_err("UTRIE_GET%s_FROM_LEAD(dummy, U+%04lx)=0x%lx instead of 0x%lx\n",
872                 make16BitTrie ? "16" : "32", (long)c, (long)value, (long)leadUnitValue);
873         }
874     }
875 }
876 
877 static void
DummyTrieTest(void)878 DummyTrieTest(void) {
879     dummyTest(true);
880     dummyTest(false);
881 }
882 
883 void
884 addTrieTest(TestNode** root);
885 
886 void
addTrieTest(TestNode ** root)887 addTrieTest(TestNode** root) {
888     addTest(root, &TrieTest, "tsutil/trietest/TrieTest");
889     addTest(root, &DummyTrieTest, "tsutil/trietest/DummyTrieTest");
890 }
891