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