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