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