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