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 */
37typedef 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 */
48typedef struct CheckRange {
49    UChar32 limit;
50    uint32_t value;
51} CheckRange;
52
53
54static uint32_t U_CALLCONV
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
80static int32_t U_CALLCONV
81_testFoldingOffset32(uint32_t data) {
82    return (int32_t)(data>>16);
83}
84
85static uint32_t U_CALLCONV
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
111static int32_t U_CALLCONV
112_testFoldingOffset16(uint32_t data) {
113    if(data&0x8000) {
114        return (int32_t)(data&0x7fff);
115    } else {
116        return 0;
117    }
118}
119
120static uint32_t U_CALLCONV
121_testEnumValue(const void *context, uint32_t value) {
122    return value^0x5555;
123}
124
125static UBool U_CALLCONV
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
139static void
140testTrieIteration(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
254static void
255testTrieRangesWithMalloc(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
443static void
444testTrieRanges(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
651static void
652testTrieRanges2(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
679static void
680testTrieRanges4(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 */
703static const SetRange
704setRanges1[]={
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
721static const CheckRange
722checkRanges1[]={
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 */
742static const SetRange
743setRanges2[]={
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
757static const CheckRange
758checkRanges2[]={
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 */
780static const SetRange
781setRanges3[]={
782    {0x31,   0xa4,   1,  FALSE},
783    {0x3400, 0x6789, 2,  FALSE},
784    {0x30000,0x34567,9,  TRUE},
785    {0x45678,0x56789,3,  TRUE}
786};
787
788static const CheckRange
789checkRanges3[]={
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
800static void
801TrieTest(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
815static int32_t U_CALLCONV
816dummyGetFoldingOffset(uint32_t data) {
817    return -1; /* never get non-initialValue data for supplementary code points */
818}
819
820static void
821dummyTest(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
873static void
874DummyTrieTest(void) {
875    dummyTest(TRUE);
876    dummyTest(FALSE);
877}
878
879void
880addTrieTest(TestNode** root);
881
882void
883addTrieTest(TestNode** root) {
884    addTest(root, &TrieTest, "tsutil/trietest/TrieTest");
885    addTest(root, &DummyTrieTest, "tsutil/trietest/DummyTrieTest");
886}
887