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 aligining 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