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-2014, 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: 2008sep01 (starting from a copy of trietest.c)
16 * created by: Markus W. Scherer
17 */
18
19 #include <stdbool.h>
20 #include <stdio.h>
21 #include "unicode/utypes.h"
22 #include "unicode/utf8.h"
23 #include "utrie2.h"
24 #include "utrie.h"
25 #include "cstring.h"
26 #include "cmemory.h"
27 #include "udataswp.h"
28 #include "cintltst.h"
29
30 void addTrie2Test(TestNode** root);
31
32 /* Values for setting possibly overlapping, out-of-order ranges of values */
33 typedef struct SetRange {
34 UChar32 start, limit;
35 uint32_t value;
36 UBool overwrite;
37 } SetRange;
38
39 /*
40 * Values for testing:
41 * value is set from the previous boundary's limit to before
42 * this boundary's limit
43 *
44 * There must be an entry with limit 0 and the intialValue.
45 * It may be preceded by an entry with negative limit and the errorValue.
46 */
47 typedef struct CheckRange {
48 UChar32 limit;
49 uint32_t value;
50 } CheckRange;
51
52 static int32_t
skipSpecialValues(const CheckRange checkRanges[],int32_t countCheckRanges)53 skipSpecialValues(const CheckRange checkRanges[], int32_t countCheckRanges) {
54 int32_t i;
55 for(i=0; i<countCheckRanges && checkRanges[i].limit<=0; ++i) {}
56 return i;
57 }
58
59 static int32_t
getSpecialValues(const CheckRange checkRanges[],int32_t countCheckRanges,uint32_t * pInitialValue,uint32_t * pErrorValue)60 getSpecialValues(const CheckRange checkRanges[], int32_t countCheckRanges,
61 uint32_t *pInitialValue, uint32_t *pErrorValue) {
62 int32_t i=0;
63 if(i<countCheckRanges && checkRanges[i].limit<0) {
64 *pErrorValue=checkRanges[i++].value;
65 } else {
66 *pErrorValue=0xbad;
67 }
68 if(i<countCheckRanges && checkRanges[i].limit==0) {
69 *pInitialValue=checkRanges[i++].value;
70 } else {
71 *pInitialValue=0;
72 }
73 return i;
74 }
75
76 /* utrie2_enum() callback, modifies a value */
77 static uint32_t U_CALLCONV
testEnumValue(const void * context,uint32_t value)78 testEnumValue(const void *context, uint32_t value) {
79 (void)context; // suppress compiler warnings about unused variable
80 return value^0x5555;
81 }
82
83 /* utrie2_enum() callback, verifies a range */
84 static UBool U_CALLCONV
testEnumRange(const void * context,UChar32 start,UChar32 end,uint32_t value)85 testEnumRange(const void *context, UChar32 start, UChar32 end, uint32_t value) {
86 const CheckRange **pb=(const CheckRange **)context;
87 const CheckRange *b=(*pb)++;
88 UChar32 limit=end+1;
89
90 value^=0x5555;
91 if(start!=(b-1)->limit || limit!=b->limit || value!=b->value) {
92 log_err("error: utrie2_enum() delivers wrong range [U+%04lx..U+%04lx].0x%lx instead of [U+%04lx..U+%04lx].0x%lx\n",
93 (long)start, (long)end, (long)value,
94 (long)(b-1)->limit, (long)b->limit-1, (long)b->value);
95 }
96 return true;
97 }
98
99 static void
testTrieEnum(const char * testName,const UTrie2 * trie,const CheckRange checkRanges[],int32_t countCheckRanges)100 testTrieEnum(const char *testName,
101 const UTrie2 *trie,
102 const CheckRange checkRanges[], int32_t countCheckRanges) {
103 (void)testName; // suppress compiler warnings about unused variable
104 /* skip over special values */
105 while(countCheckRanges>0 && checkRanges[0].limit<=0) {
106 ++checkRanges;
107 --countCheckRanges;
108 }
109 utrie2_enum(trie, testEnumValue, testEnumRange, &checkRanges);
110 }
111
112 /* verify all expected values via UTRIE2_GETxx() */
113 static void
testTrieGetters(const char * testName,const UTrie2 * trie,UTrie2ValueBits valueBits,const CheckRange checkRanges[],int32_t countCheckRanges)114 testTrieGetters(const char *testName,
115 const UTrie2 *trie, UTrie2ValueBits valueBits,
116 const CheckRange checkRanges[], int32_t countCheckRanges) {
117 uint32_t initialValue, errorValue;
118 uint32_t value, value2;
119 UChar32 start, limit;
120 int32_t i, countSpecials;
121
122 UBool isFrozen=utrie2_isFrozen(trie);
123 const char *const typeName= isFrozen ? "frozen trie" : "newTrie";
124
125 countSpecials=getSpecialValues(checkRanges, countCheckRanges, &initialValue, &errorValue);
126
127 start=0;
128 for(i=countSpecials; i<countCheckRanges; ++i) {
129 limit=checkRanges[i].limit;
130 value=checkRanges[i].value;
131
132 while(start<limit) {
133 if(isFrozen) {
134 if(start<=0xffff) {
135 if(!U_IS_LEAD(start)) {
136 if(valueBits==UTRIE2_16_VALUE_BITS) {
137 value2=UTRIE2_GET16_FROM_U16_SINGLE_LEAD(trie, start);
138 } else {
139 value2=UTRIE2_GET32_FROM_U16_SINGLE_LEAD(trie, start);
140 }
141 if(value!=value2) {
142 log_err("error: %s(%s).fromBMP(U+%04lx)==0x%lx instead of 0x%lx\n",
143 typeName, testName, (long)start, (long)value2, (long)value);
144 }
145 }
146 } else {
147 if(valueBits==UTRIE2_16_VALUE_BITS) {
148 value2=UTRIE2_GET16_FROM_SUPP(trie, start);
149 } else {
150 value2=UTRIE2_GET32_FROM_SUPP(trie, start);
151 }
152 if(value!=value2) {
153 log_err("error: %s(%s).fromSupp(U+%04lx)==0x%lx instead of 0x%lx\n",
154 typeName, testName, (long)start, (long)value2, (long)value);
155 }
156 }
157 if(valueBits==UTRIE2_16_VALUE_BITS) {
158 value2=UTRIE2_GET16(trie, start);
159 } else {
160 value2=UTRIE2_GET32(trie, start);
161 }
162 if(value!=value2) {
163 log_err("error: %s(%s).get(U+%04lx)==0x%lx instead of 0x%lx\n",
164 typeName, testName, (long)start, (long)value2, (long)value);
165 }
166 }
167 value2=utrie2_get32(trie, start);
168 if(value!=value2) {
169 log_err("error: %s(%s).get32(U+%04lx)==0x%lx instead of 0x%lx\n",
170 typeName, testName, (long)start, (long)value2, (long)value);
171 }
172 ++start;
173 }
174 }
175
176 if(isFrozen) {
177 /* test linear ASCII range from the data array pointer (access to "internal" field) */
178 start=0;
179 for(i=countSpecials; i<countCheckRanges && start<=0x7f; ++i) {
180 limit=checkRanges[i].limit;
181 value=checkRanges[i].value;
182
183 while(start<limit && start<=0x7f) {
184 if(valueBits==UTRIE2_16_VALUE_BITS) {
185 value2=trie->data16[start];
186 } else {
187 value2=trie->data32[start];
188 }
189 if(value!=value2) {
190 log_err("error: %s(%s).asciiData[U+%04lx]==0x%lx instead of 0x%lx\n",
191 typeName, testName, (long)start, (long)value2, (long)value);
192 }
193 ++start;
194 }
195 }
196 while(start<=0xbf) {
197 if(valueBits==UTRIE2_16_VALUE_BITS) {
198 value2=trie->data16[start];
199 } else {
200 value2=trie->data32[start];
201 }
202 if(errorValue!=value2) {
203 log_err("error: %s(%s).badData[U+%04lx]==0x%lx instead of 0x%lx\n",
204 typeName, testName, (long)start, (long)value2, (long)errorValue);
205 }
206 ++start;
207 }
208 }
209
210 if(0!=strncmp(testName, "dummy", 5) && 0!=strncmp(testName, "trie1", 5)) {
211 /* test values for lead surrogate code units */
212 for(start=0xd7ff; start<0xdc01; ++start) {
213 switch(start) {
214 case 0xd7ff:
215 case 0xdc00:
216 value=errorValue;
217 break;
218 case 0xd800:
219 value=90;
220 break;
221 case 0xd999:
222 value=94;
223 break;
224 case 0xdbff:
225 value=99;
226 break;
227 default:
228 value=initialValue;
229 break;
230 }
231 if(isFrozen && U_IS_LEAD(start)) {
232 if(valueBits==UTRIE2_16_VALUE_BITS) {
233 value2=UTRIE2_GET16_FROM_U16_SINGLE_LEAD(trie, start);
234 } else {
235 value2=UTRIE2_GET32_FROM_U16_SINGLE_LEAD(trie, start);
236 }
237 if(value2!=value) {
238 log_err("error: %s(%s).LSCU(U+%04lx)==0x%lx instead of 0x%lx\n",
239 typeName, testName, (long)start, (long)value2, (long)value);
240 }
241 }
242 value2=utrie2_get32FromLeadSurrogateCodeUnit(trie, start);
243 if(value2!=value) {
244 log_err("error: %s(%s).lscu(U+%04lx)==0x%lx instead of 0x%lx\n",
245 typeName, testName, (long)start, (long)value2, (long)value);
246 }
247 }
248 }
249
250 /* test errorValue */
251 if(isFrozen) {
252 if(valueBits==UTRIE2_16_VALUE_BITS) {
253 value=UTRIE2_GET16(trie, -1);
254 value2=UTRIE2_GET16(trie, 0x110000);
255 } else {
256 value=UTRIE2_GET32(trie, -1);
257 value2=UTRIE2_GET32(trie, 0x110000);
258 }
259 if(value!=errorValue || value2!=errorValue) {
260 log_err("error: %s(%s).get(out of range) != errorValue\n",
261 typeName, testName);
262 }
263 }
264 value=utrie2_get32(trie, -1);
265 value2=utrie2_get32(trie, 0x110000);
266 if(value!=errorValue || value2!=errorValue) {
267 log_err("error: %s(%s).get32(out of range) != errorValue\n",
268 typeName, testName);
269 }
270 }
271
272 static void
testTrieUTF16(const char * testName,const UTrie2 * trie,UTrie2ValueBits valueBits,const CheckRange checkRanges[],int32_t countCheckRanges)273 testTrieUTF16(const char *testName,
274 const UTrie2 *trie, UTrie2ValueBits valueBits,
275 const CheckRange checkRanges[], int32_t countCheckRanges) {
276 UChar s[200];
277 uint32_t values[100];
278
279 const UChar *p, *limit;
280
281 uint32_t value;
282 UChar32 prevCP, c, c2;
283 int32_t i, length, sIndex, countValues;
284
285 /* write a string */
286 prevCP=0;
287 length=countValues=0;
288 for(i=skipSpecialValues(checkRanges, countCheckRanges); i<countCheckRanges; ++i) {
289 value=checkRanges[i].value;
290 /* write three code points */
291 U16_APPEND_UNSAFE(s, length, prevCP); /* start of the range */
292 values[countValues++]=value;
293 c=checkRanges[i].limit;
294 prevCP=(prevCP+c)/2; /* middle of the range */
295 U16_APPEND_UNSAFE(s, length, prevCP);
296 values[countValues++]=value;
297 prevCP=c;
298 --c; /* end of the range */
299 U16_APPEND_UNSAFE(s, length, c);
300 values[countValues++]=value;
301 }
302 limit=s+length;
303
304 /* try forward */
305 p=s;
306 i=0;
307 while(p<limit) {
308 sIndex=(int32_t)(p-s);
309 U16_NEXT(s, sIndex, length, c2);
310 c=0x33;
311 if(valueBits==UTRIE2_16_VALUE_BITS) {
312 UTRIE2_U16_NEXT16(trie, p, limit, c, value);
313 } else {
314 UTRIE2_U16_NEXT32(trie, p, limit, c, value);
315 }
316 if(value!=values[i]) {
317 log_err("error: wrong value from UTRIE2_NEXT(%s)(U+%04lx): 0x%lx instead of 0x%lx\n",
318 testName, (long)c, (long)value, (long)values[i]);
319 }
320 if(c!=c2) {
321 log_err("error: wrong code point from UTRIE2_NEXT(%s): U+%04lx != U+%04lx\n",
322 testName, (long)c, (long)c2);
323 continue;
324 }
325 ++i;
326 }
327
328 /* try backward */
329 p=limit;
330 i=countValues;
331 while(s<p) {
332 --i;
333 sIndex=(int32_t)(p-s);
334 U16_PREV(s, 0, sIndex, c2);
335 c=0x33;
336 if(valueBits==UTRIE2_16_VALUE_BITS) {
337 UTRIE2_U16_PREV16(trie, s, p, c, value);
338 } else {
339 UTRIE2_U16_PREV32(trie, s, p, c, value);
340 }
341 if(value!=values[i]) {
342 log_err("error: wrong value from UTRIE2_PREV(%s)(U+%04lx): 0x%lx instead of 0x%lx\n",
343 testName, (long)c, (long)value, (long)values[i]);
344 }
345 if(c!=c2) {
346 log_err("error: wrong code point from UTRIE2_PREV(%s): U+%04lx != U+%04lx\n",
347 testName, c, c2);
348 }
349 }
350 }
351
352 static void
testTrieUTF8(const char * testName,const UTrie2 * trie,UTrie2ValueBits valueBits,const CheckRange checkRanges[],int32_t countCheckRanges)353 testTrieUTF8(const char *testName,
354 const UTrie2 *trie, UTrie2ValueBits valueBits,
355 const CheckRange checkRanges[], int32_t countCheckRanges) {
356 // Note: The byte sequence comments refer to the original UTF-8 definition.
357 // Starting with ICU 60, any sequence that is not a prefix of a valid one
358 // is treated as multiple single-byte errors.
359 // For testing, we only rely on U8_... and UTrie2 UTF-8 macros
360 // iterating consistently.
361 static const uint8_t illegal[]={
362 0xc0, 0x80, /* non-shortest U+0000 */
363 0xc1, 0xbf, /* non-shortest U+007f */
364 0xc2, /* truncated */
365 0xe0, 0x90, 0x80, /* non-shortest U+0400 */
366 0xe0, 0xa0, /* truncated */
367 0xed, 0xa0, 0x80, /* lead surrogate U+d800 */
368 0xed, 0xbf, 0xbf, /* trail surrogate U+dfff */
369 0xf0, 0x8f, 0xbf, 0xbf, /* non-shortest U+ffff */
370 0xf0, 0x90, 0x80, /* truncated */
371 0xf4, 0x90, 0x80, 0x80, /* beyond-Unicode U+110000 */
372 0xf8, 0x80, 0x80, 0x80, /* truncated */
373 0xf8, 0x80, 0x80, 0x80, 0x80, /* 5-byte UTF-8 */
374 0xfd, 0xbf, 0xbf, 0xbf, 0xbf, /* truncated */
375 0xfd, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, /* 6-byte UTF-8 */
376 0xfe,
377 0xff
378 };
379 uint8_t s[600];
380 uint32_t values[200];
381
382 const uint8_t *p, *limit;
383
384 uint32_t initialValue, errorValue;
385 uint32_t value, bytes;
386 UChar32 prevCP, c;
387 int32_t i, countSpecials, length, countValues;
388 int32_t prev8, i8;
389
390 countSpecials=getSpecialValues(checkRanges, countCheckRanges, &initialValue, &errorValue);
391
392 /* write a string */
393 prevCP=0;
394 length=countValues=0;
395 /* first a couple of trail bytes in lead position */
396 s[length++]=0x80;
397 values[countValues++]=errorValue;
398 s[length++]=0xbf;
399 values[countValues++]=errorValue;
400 prev8=i8=0;
401 for(i=countSpecials; i<countCheckRanges; ++i) {
402 value=checkRanges[i].value;
403 /* write three legal (or surrogate) code points */
404 U8_APPEND_UNSAFE(s, length, prevCP); /* start of the range */
405 if(U_IS_SURROGATE(prevCP)) {
406 // A surrogate byte sequence counts as 3 single-byte errors.
407 values[countValues++]=errorValue;
408 values[countValues++]=errorValue;
409 values[countValues++]=errorValue;
410 } else {
411 values[countValues++]=value;
412 }
413 c=checkRanges[i].limit;
414 prevCP=(prevCP+c)/2; /* middle of the range */
415 U8_APPEND_UNSAFE(s, length, prevCP);
416 if(U_IS_SURROGATE(prevCP)) {
417 // A surrogate byte sequence counts as 3 single-byte errors.
418 values[countValues++]=errorValue;
419 values[countValues++]=errorValue;
420 values[countValues++]=errorValue;
421 } else {
422 values[countValues++]=value;
423 }
424 prevCP=c;
425 --c; /* end of the range */
426 U8_APPEND_UNSAFE(s, length, c);
427 if(U_IS_SURROGATE(c)) {
428 // A surrogate byte sequence counts as 3 single-byte errors.
429 values[countValues++]=errorValue;
430 values[countValues++]=errorValue;
431 values[countValues++]=errorValue;
432 } else {
433 values[countValues++]=value;
434 }
435 /* write an illegal byte sequence */
436 if(i8<(int32_t)sizeof(illegal)) {
437 U8_FWD_1(illegal, i8, sizeof(illegal));
438 while(prev8<i8) {
439 s[length++]=illegal[prev8++];
440 }
441 values[countValues++]=errorValue;
442 }
443 }
444 /* write the remaining illegal byte sequences */
445 while(i8<(int32_t)sizeof(illegal)) {
446 U8_FWD_1(illegal, i8, sizeof(illegal));
447 while(prev8<i8) {
448 s[length++]=illegal[prev8++];
449 }
450 values[countValues++]=errorValue;
451 }
452 limit=s+length;
453
454 /* try forward */
455 p=s;
456 i=0;
457 while(p<limit) {
458 prev8=i8=(int32_t)(p-s);
459 U8_NEXT(s, i8, length, c);
460 if(valueBits==UTRIE2_16_VALUE_BITS) {
461 UTRIE2_U8_NEXT16(trie, p, limit, value);
462 } else {
463 UTRIE2_U8_NEXT32(trie, p, limit, value);
464 }
465 bytes=0;
466 if(value!=values[i] || i8!=(p-s)) {
467 int32_t k=prev8;
468 while(k<i8) {
469 bytes=(bytes<<8)|s[k++];
470 }
471 }
472 if(value!=values[i]) {
473 log_err("error: wrong value from UTRIE2_U8_NEXT(%s)(from %d %lx->U+%04lx) (read %d bytes): "
474 "0x%lx instead of 0x%lx\n",
475 testName, (int)prev8, (unsigned long)bytes, (long)c, (int)((p-s)-prev8),
476 (long)value, (long)values[i]);
477 }
478 if(i8!=(p-s)) {
479 log_err("error: wrong end index from UTRIE2_U8_NEXT(%s)(from %d %lx->U+%04lx): %ld != %ld\n",
480 testName, (int)prev8, (unsigned long)bytes, (long)c, (long)(p-s), (long)i8);
481 continue;
482 }
483 ++i;
484 }
485
486 /* try backward */
487 p=limit;
488 i=countValues;
489 while(s<p) {
490 --i;
491 prev8=i8=(int32_t)(p-s);
492 U8_PREV(s, 0, i8, c);
493 if(valueBits==UTRIE2_16_VALUE_BITS) {
494 UTRIE2_U8_PREV16(trie, s, p, value);
495 } else {
496 UTRIE2_U8_PREV32(trie, s, p, value);
497 }
498 bytes=0;
499 if(value!=values[i] || i8!=(p-s)) {
500 int32_t k=i8;
501 while(k<prev8) {
502 bytes=(bytes<<8)|s[k++];
503 }
504 }
505 if(value!=values[i]) {
506 log_err("error: wrong value from UTRIE2_U8_PREV(%s)(from %d %lx->U+%04lx) (read %d bytes): "
507 ": 0x%lx instead of 0x%lx\n",
508 testName, (int)prev8, (unsigned long)bytes, (long)c, (int)(prev8-(p-s)),
509 (long)value, (long)values[i]);
510 }
511 if(i8!=(p-s)) {
512 log_err("error: wrong end index from UTRIE2_U8_PREV(%s)(from %d %lx->U+%04lx): %ld != %ld\n",
513 testName, (int)prev8, (unsigned long)bytes, (long)c, (long)(p-s), (long)i8);
514 continue;
515 }
516 }
517 }
518
519 static void
testFrozenTrie(const char * testName,UTrie2 * trie,UTrie2ValueBits valueBits,const CheckRange checkRanges[],int32_t countCheckRanges)520 testFrozenTrie(const char *testName,
521 UTrie2 *trie, UTrie2ValueBits valueBits,
522 const CheckRange checkRanges[], int32_t countCheckRanges) {
523 UErrorCode errorCode;
524 uint32_t value, value2;
525
526 if(!utrie2_isFrozen(trie)) {
527 log_err("error: utrie2_isFrozen(frozen %s) returned false (not frozen)\n",
528 testName);
529 return;
530 }
531
532 testTrieGetters(testName, trie, valueBits, checkRanges, countCheckRanges);
533 testTrieEnum(testName, trie, checkRanges, countCheckRanges);
534 testTrieUTF16(testName, trie, valueBits, checkRanges, countCheckRanges);
535 testTrieUTF8(testName, trie, valueBits, checkRanges, countCheckRanges);
536
537 errorCode=U_ZERO_ERROR;
538 value=utrie2_get32(trie, 1);
539 utrie2_set32(trie, 1, 234, &errorCode);
540 value2=utrie2_get32(trie, 1);
541 if(errorCode!=U_NO_WRITE_PERMISSION || value2!=value) {
542 log_err("error: utrie2_set32(frozen %s) failed: it set %s != U_NO_WRITE_PERMISSION\n",
543 testName, u_errorName(errorCode));
544 return;
545 }
546
547 errorCode=U_ZERO_ERROR;
548 utrie2_setRange32(trie, 1, 5, 234, true, &errorCode);
549 value2=utrie2_get32(trie, 1);
550 if(errorCode!=U_NO_WRITE_PERMISSION || value2!=value) {
551 log_err("error: utrie2_setRange32(frozen %s) failed: it set %s != U_NO_WRITE_PERMISSION\n",
552 testName, u_errorName(errorCode));
553 return;
554 }
555
556 errorCode=U_ZERO_ERROR;
557 value=utrie2_get32FromLeadSurrogateCodeUnit(trie, 0xd801);
558 utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xd801, 234, &errorCode);
559 value2=utrie2_get32FromLeadSurrogateCodeUnit(trie, 0xd801);
560 if(errorCode!=U_NO_WRITE_PERMISSION || value2!=value) {
561 log_err("error: utrie2_set32ForLeadSurrogateCodeUnit(frozen %s) failed: "
562 "it set %s != U_NO_WRITE_PERMISSION\n",
563 testName, u_errorName(errorCode));
564 return;
565 }
566 }
567
568 static void
testNewTrie(const char * testName,const UTrie2 * trie,const CheckRange checkRanges[],int32_t countCheckRanges)569 testNewTrie(const char *testName, const UTrie2 *trie,
570 const CheckRange checkRanges[], int32_t countCheckRanges) {
571 /* The valueBits are ignored for an unfrozen trie. */
572 testTrieGetters(testName, trie, UTRIE2_COUNT_VALUE_BITS, checkRanges, countCheckRanges);
573 testTrieEnum(testName, trie, checkRanges, countCheckRanges);
574 }
575
576 static void
testTrieSerialize(const char * testName,UTrie2 * trie,UTrie2ValueBits valueBits,UBool withSwap,const CheckRange checkRanges[],int32_t countCheckRanges)577 testTrieSerialize(const char *testName,
578 UTrie2 *trie, UTrie2ValueBits valueBits,
579 UBool withSwap,
580 const CheckRange checkRanges[], int32_t countCheckRanges) {
581 uint32_t storage[10000];
582 int32_t length1, length2, length3;
583 UTrie2ValueBits otherValueBits;
584 UErrorCode errorCode;
585
586 /* clone the trie so that the caller can reuse the original */
587 errorCode=U_ZERO_ERROR;
588 trie=utrie2_clone(trie, &errorCode);
589 if(U_FAILURE(errorCode)) {
590 log_err("error: utrie2_clone(unfrozen %s) failed - %s\n",
591 testName, u_errorName(errorCode));
592 return;
593 }
594
595 /*
596 * This is not a loop, but simply a block that we can exit with "break"
597 * when something goes wrong.
598 */
599 do {
600 errorCode=U_ZERO_ERROR;
601 utrie2_serialize(trie, storage, sizeof(storage), &errorCode);
602 if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
603 log_err("error: utrie2_serialize(unfrozen %s) set %s != U_ILLEGAL_ARGUMENT_ERROR\n",
604 testName, u_errorName(errorCode));
605 break;
606 }
607 errorCode=U_ZERO_ERROR;
608 utrie2_freeze(trie, valueBits, &errorCode);
609 if(U_FAILURE(errorCode) || !utrie2_isFrozen(trie)) {
610 log_err("error: utrie2_freeze(%s) failed: %s isFrozen: %d\n",
611 testName, u_errorName(errorCode), utrie2_isFrozen(trie));
612 break;
613 }
614 otherValueBits= valueBits==UTRIE2_16_VALUE_BITS ? UTRIE2_32_VALUE_BITS : UTRIE2_16_VALUE_BITS;
615 utrie2_freeze(trie, otherValueBits, &errorCode);
616 if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
617 log_err("error: utrie2_freeze(already-frozen with other valueBits %s) "
618 "set %s != U_ILLEGAL_ARGUMENT_ERROR\n",
619 testName, u_errorName(errorCode));
620 break;
621 }
622 errorCode=U_ZERO_ERROR;
623 if(withSwap) {
624 /* clone a frozen trie */
625 UTrie2 *clone=utrie2_clone(trie, &errorCode);
626 if(U_FAILURE(errorCode)) {
627 log_err("error: cloning a frozen UTrie2 failed (%s) - %s\n",
628 testName, u_errorName(errorCode));
629 errorCode=U_ZERO_ERROR; /* continue with the original */
630 } else {
631 utrie2_close(trie);
632 trie=clone;
633 }
634 }
635 length1=utrie2_serialize(trie, NULL, 0, &errorCode);
636 if(errorCode!=U_BUFFER_OVERFLOW_ERROR) {
637 log_err("error: utrie2_serialize(%s) preflighting set %s != U_BUFFER_OVERFLOW_ERROR\n",
638 testName, u_errorName(errorCode));
639 break;
640 }
641 errorCode=U_ZERO_ERROR;
642 length2=utrie2_serialize(trie, storage, sizeof(storage), &errorCode);
643 if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
644 log_err("error: utrie2_serialize(%s) needs more memory\n", testName);
645 break;
646 }
647 if(U_FAILURE(errorCode)) {
648 log_err("error: utrie2_serialize(%s) failed: %s\n", testName, u_errorName(errorCode));
649 break;
650 }
651 if(length1!=length2) {
652 log_err("error: trie serialization (%s) lengths different: "
653 "preflight vs. serialize\n", testName);
654 break;
655 }
656
657 testFrozenTrie(testName, trie, valueBits, checkRanges, countCheckRanges);
658 utrie2_close(trie);
659 trie=NULL;
660
661 if(withSwap) {
662 uint32_t swapped[10000];
663 int32_t swappedLength;
664
665 UDataSwapper *ds;
666
667 /* swap to opposite-endian */
668 uprv_memset(swapped, 0x55, length2);
669 ds=udata_openSwapper(U_IS_BIG_ENDIAN, U_CHARSET_FAMILY,
670 !U_IS_BIG_ENDIAN, U_CHARSET_FAMILY, &errorCode);
671 swappedLength=utrie2_swap(ds, storage, -1, NULL, &errorCode);
672 if(U_FAILURE(errorCode) || swappedLength!=length2) {
673 log_err("error: utrie2_swap(%s to OE preflighting) failed (%s) "
674 "or before/after lengths different\n",
675 testName, u_errorName(errorCode));
676 udata_closeSwapper(ds);
677 break;
678 }
679 swappedLength=utrie2_swap(ds, storage, length2, swapped, &errorCode);
680 udata_closeSwapper(ds);
681 if(U_FAILURE(errorCode) || swappedLength!=length2) {
682 log_err("error: utrie2_swap(%s to OE) failed (%s) or before/after lengths different\n",
683 testName, u_errorName(errorCode));
684 break;
685 }
686
687 /* swap back to platform-endian */
688 uprv_memset(storage, 0xaa, length2);
689 ds=udata_openSwapper(!U_IS_BIG_ENDIAN, U_CHARSET_FAMILY,
690 U_IS_BIG_ENDIAN, U_CHARSET_FAMILY, &errorCode);
691 swappedLength=utrie2_swap(ds, swapped, -1, NULL, &errorCode);
692 if(U_FAILURE(errorCode) || swappedLength!=length2) {
693 log_err("error: utrie2_swap(%s to PE preflighting) failed (%s) "
694 "or before/after lengths different\n",
695 testName, u_errorName(errorCode));
696 udata_closeSwapper(ds);
697 break;
698 }
699 swappedLength=utrie2_swap(ds, swapped, length2, storage, &errorCode);
700 udata_closeSwapper(ds);
701 if(U_FAILURE(errorCode) || swappedLength!=length2) {
702 log_err("error: utrie2_swap(%s to PE) failed (%s) or before/after lengths different\n",
703 testName, u_errorName(errorCode));
704 break;
705 }
706 }
707
708 trie=utrie2_openFromSerialized(valueBits, storage, length2, &length3, &errorCode);
709 if(U_FAILURE(errorCode)) {
710 log_err("error: utrie2_openFromSerialized(%s) failed, %s\n", testName, u_errorName(errorCode));
711 break;
712 }
713 if((valueBits==UTRIE2_16_VALUE_BITS)!=(trie->data32==NULL)) {
714 log_err("error: trie serialization (%s) did not preserve 32-bitness\n", testName);
715 break;
716 }
717 if(length2!=length3) {
718 log_err("error: trie serialization (%s) lengths different: "
719 "serialize vs. unserialize\n", testName);
720 break;
721 }
722 /* overwrite the storage that is not supposed to be needed */
723 uprv_memset((char *)storage+length3, 0xfa, (int32_t)(sizeof(storage)-length3));
724
725 utrie2_freeze(trie, valueBits, &errorCode);
726 if(U_FAILURE(errorCode) || !utrie2_isFrozen(trie)) {
727 log_err("error: utrie2_freeze(unserialized %s) failed: %s isFrozen: %d\n",
728 testName, u_errorName(errorCode), utrie2_isFrozen(trie));
729 break;
730 }
731 utrie2_freeze(trie, otherValueBits, &errorCode);
732 if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
733 log_err("error: utrie2_freeze(unserialized with other valueBits %s) "
734 "set %s != U_ILLEGAL_ARGUMENT_ERROR\n",
735 testName, u_errorName(errorCode));
736 break;
737 }
738 errorCode=U_ZERO_ERROR;
739 if(withSwap) {
740 /* clone an unserialized trie */
741 UTrie2 *clone=utrie2_clone(trie, &errorCode);
742 if(U_FAILURE(errorCode)) {
743 log_err("error: utrie2_clone(unserialized %s) failed - %s\n",
744 testName, u_errorName(errorCode));
745 errorCode=U_ZERO_ERROR;
746 /* no need to break: just test the original trie */
747 } else {
748 utrie2_close(trie);
749 trie=clone;
750 uprv_memset(storage, 0, sizeof(storage));
751 }
752 }
753 testFrozenTrie(testName, trie, valueBits, checkRanges, countCheckRanges);
754 {
755 /* clone-as-thawed an unserialized trie */
756 UTrie2 *clone=utrie2_cloneAsThawed(trie, &errorCode);
757 if(U_FAILURE(errorCode) || utrie2_isFrozen(clone)) {
758 log_err("error: utrie2_cloneAsThawed(unserialized %s) failed - "
759 "%s (isFrozen: %d)\n",
760 testName, u_errorName(errorCode), clone!=NULL && utrie2_isFrozen(trie));
761 break;
762 } else {
763 utrie2_close(trie);
764 trie=clone;
765 }
766 }
767 {
768 uint32_t value, value2;
769
770 value=utrie2_get32(trie, 0xa1);
771 utrie2_set32(trie, 0xa1, 789, &errorCode);
772 value2=utrie2_get32(trie, 0xa1);
773 utrie2_set32(trie, 0xa1, value, &errorCode);
774 if(U_FAILURE(errorCode) || value2!=789) {
775 log_err("error: modifying a cloneAsThawed UTrie2 (%s) failed - %s\n",
776 testName, u_errorName(errorCode));
777 }
778 }
779 testNewTrie(testName, trie, checkRanges, countCheckRanges);
780 } while(0);
781
782 utrie2_close(trie);
783 }
784
785 static UTrie2 *
testTrieSerializeAllValueBits(const char * testName,UTrie2 * trie,UBool withClone,const CheckRange checkRanges[],int32_t countCheckRanges)786 testTrieSerializeAllValueBits(const char *testName,
787 UTrie2 *trie, UBool withClone,
788 const CheckRange checkRanges[], int32_t countCheckRanges) {
789 char name[40];
790
791 /* verify that all the expected values are in the unfrozen trie */
792 testNewTrie(testName, trie, checkRanges, countCheckRanges);
793
794 /*
795 * Test with both valueBits serializations,
796 * and that utrie2_serialize() can be called multiple times.
797 */
798 uprv_strcpy(name, testName);
799 uprv_strcat(name, ".16");
800 testTrieSerialize(name, trie,
801 UTRIE2_16_VALUE_BITS, withClone,
802 checkRanges, countCheckRanges);
803
804 if(withClone) {
805 /*
806 * try cloning after the first serialization;
807 * clone-as-thawed just to sometimes try it on an unfrozen trie
808 */
809 UErrorCode errorCode=U_ZERO_ERROR;
810 UTrie2 *clone=utrie2_cloneAsThawed(trie, &errorCode);
811 if(U_FAILURE(errorCode)) {
812 log_err("error: utrie2_cloneAsThawed(%s) after serialization failed - %s\n",
813 testName, u_errorName(errorCode));
814 } else {
815 utrie2_close(trie);
816 trie=clone;
817
818 testNewTrie(testName, trie, checkRanges, countCheckRanges);
819 }
820 }
821
822 uprv_strcpy(name, testName);
823 uprv_strcat(name, ".32");
824 testTrieSerialize(name, trie,
825 UTRIE2_32_VALUE_BITS, withClone,
826 checkRanges, countCheckRanges);
827
828 return trie; /* could be the clone */
829 }
830
831 static UTrie2 *
makeTrieWithRanges(const char * testName,UBool withClone,const SetRange setRanges[],int32_t countSetRanges,const CheckRange checkRanges[],int32_t countCheckRanges)832 makeTrieWithRanges(const char *testName, UBool withClone,
833 const SetRange setRanges[], int32_t countSetRanges,
834 const CheckRange checkRanges[], int32_t countCheckRanges) {
835 UTrie2 *trie;
836 uint32_t initialValue, errorValue;
837 uint32_t value;
838 UChar32 start, limit;
839 int32_t i;
840 UErrorCode errorCode;
841 UBool overwrite;
842
843 log_verbose("\ntesting Trie '%s'\n", testName);
844 errorCode=U_ZERO_ERROR;
845 getSpecialValues(checkRanges, countCheckRanges, &initialValue, &errorValue);
846 trie=utrie2_open(initialValue, errorValue, &errorCode);
847 if(U_FAILURE(errorCode)) {
848 log_err("error: utrie2_open(%s) failed: %s\n", testName, u_errorName(errorCode));
849 return NULL;
850 }
851
852 /* set values from setRanges[] */
853 for(i=0; i<countSetRanges; ++i) {
854 if(withClone && i==countSetRanges/2) {
855 /* switch to a clone in the middle of setting values */
856 UTrie2 *clone=utrie2_clone(trie, &errorCode);
857 if(U_FAILURE(errorCode)) {
858 log_err("error: utrie2_clone(%s) failed - %s\n",
859 testName, u_errorName(errorCode));
860 errorCode=U_ZERO_ERROR; /* continue with the original */
861 } else {
862 utrie2_close(trie);
863 trie=clone;
864 }
865 }
866 start=setRanges[i].start;
867 limit=setRanges[i].limit;
868 value=setRanges[i].value;
869 overwrite=setRanges[i].overwrite;
870 if((limit-start)==1 && overwrite) {
871 utrie2_set32(trie, start, value, &errorCode);
872 } else {
873 utrie2_setRange32(trie, start, limit-1, value, overwrite, &errorCode);
874 }
875 }
876
877 /* set some values for lead surrogate code units */
878 utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xd800, 90, &errorCode);
879 utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xd999, 94, &errorCode);
880 utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xdbff, 99, &errorCode);
881 if(U_SUCCESS(errorCode)) {
882 return trie;
883 } else {
884 log_err("error: setting values into a trie (%s) failed - %s\n",
885 testName, u_errorName(errorCode));
886 utrie2_close(trie);
887 return NULL;
888 }
889 }
890
891 static void
testTrieRanges(const char * testName,UBool withClone,const SetRange setRanges[],int32_t countSetRanges,const CheckRange checkRanges[],int32_t countCheckRanges)892 testTrieRanges(const char *testName, UBool withClone,
893 const SetRange setRanges[], int32_t countSetRanges,
894 const CheckRange checkRanges[], int32_t countCheckRanges) {
895 UTrie2 *trie=makeTrieWithRanges(testName, withClone,
896 setRanges, countSetRanges,
897 checkRanges, countCheckRanges);
898 if(trie!=NULL) {
899 trie=testTrieSerializeAllValueBits(testName, trie, withClone,
900 checkRanges, countCheckRanges);
901 utrie2_close(trie);
902 }
903 }
904
905 /* test data ----------------------------------------------------------------*/
906
907 /* set consecutive ranges, even with value 0 */
908 static const SetRange
909 setRanges1[]={
910 { 0, 0x40, 0, false },
911 { 0x40, 0xe7, 0x1234, false },
912 { 0xe7, 0x3400, 0, false },
913 { 0x3400, 0x9fa6, 0x6162, false },
914 { 0x9fa6, 0xda9e, 0x3132, false },
915 { 0xdada, 0xeeee, 0x87ff, false },
916 { 0xeeee, 0x11111, 1, false },
917 { 0x11111, 0x44444, 0x6162, false },
918 { 0x44444, 0x60003, 0, false },
919 { 0xf0003, 0xf0004, 0xf, false },
920 { 0xf0004, 0xf0006, 0x10, false },
921 { 0xf0006, 0xf0007, 0x11, false },
922 { 0xf0007, 0xf0040, 0x12, false },
923 { 0xf0040, 0x110000, 0, false }
924 };
925
926 static const CheckRange
927 checkRanges1[]={
928 { 0, 0 },
929 { 0x40, 0 },
930 { 0xe7, 0x1234 },
931 { 0x3400, 0 },
932 { 0x9fa6, 0x6162 },
933 { 0xda9e, 0x3132 },
934 { 0xdada, 0 },
935 { 0xeeee, 0x87ff },
936 { 0x11111, 1 },
937 { 0x44444, 0x6162 },
938 { 0xf0003, 0 },
939 { 0xf0004, 0xf },
940 { 0xf0006, 0x10 },
941 { 0xf0007, 0x11 },
942 { 0xf0040, 0x12 },
943 { 0x110000, 0 }
944 };
945
946 /* set some interesting overlapping ranges */
947 static const SetRange
948 setRanges2[]={
949 { 0x21, 0x7f, 0x5555, true },
950 { 0x2f800, 0x2fedc, 0x7a, true },
951 { 0x72, 0xdd, 3, true },
952 { 0xdd, 0xde, 4, false },
953 { 0x201, 0x240, 6, true }, /* 3 consecutive blocks with the same pattern but */
954 { 0x241, 0x280, 6, true }, /* discontiguous value ranges, testing utrie2_enum() */
955 { 0x281, 0x2c0, 6, true },
956 { 0x2f987, 0x2fa98, 5, true },
957 { 0x2f777, 0x2f883, 0, true },
958 { 0x2f900, 0x2ffaa, 1, false },
959 { 0x2ffaa, 0x2ffab, 2, true },
960 { 0x2ffbb, 0x2ffc0, 7, true }
961 };
962
963 static const CheckRange
964 checkRanges2[]={
965 { 0, 0 },
966 { 0x21, 0 },
967 { 0x72, 0x5555 },
968 { 0xdd, 3 },
969 { 0xde, 4 },
970 { 0x201, 0 },
971 { 0x240, 6 },
972 { 0x241, 0 },
973 { 0x280, 6 },
974 { 0x281, 0 },
975 { 0x2c0, 6 },
976 { 0x2f883, 0 },
977 { 0x2f987, 0x7a },
978 { 0x2fa98, 5 },
979 { 0x2fedc, 0x7a },
980 { 0x2ffaa, 1 },
981 { 0x2ffab, 2 },
982 { 0x2ffbb, 0 },
983 { 0x2ffc0, 7 },
984 { 0x110000, 0 }
985 };
986
987 static const CheckRange
988 checkRanges2_d800[]={
989 { 0x10000, 0 },
990 { 0x10400, 0 }
991 };
992
993 static const CheckRange
994 checkRanges2_d87e[]={
995 { 0x2f800, 6 },
996 { 0x2f883, 0 },
997 { 0x2f987, 0x7a },
998 { 0x2fa98, 5 },
999 { 0x2fc00, 0x7a }
1000 };
1001
1002 static const CheckRange
1003 checkRanges2_d87f[]={
1004 { 0x2fc00, 0 },
1005 { 0x2fedc, 0x7a },
1006 { 0x2ffaa, 1 },
1007 { 0x2ffab, 2 },
1008 { 0x2ffbb, 0 },
1009 { 0x2ffc0, 7 },
1010 { 0x30000, 0 }
1011 };
1012
1013 static const CheckRange
1014 checkRanges2_dbff[]={
1015 { 0x10fc00, 0 },
1016 { 0x110000, 0 }
1017 };
1018
1019 /* use a non-zero initial value */
1020 static const SetRange
1021 setRanges3[]={
1022 { 0x31, 0xa4, 1, false },
1023 { 0x3400, 0x6789, 2, false },
1024 { 0x8000, 0x89ab, 9, true },
1025 { 0x9000, 0xa000, 4, true },
1026 { 0xabcd, 0xbcde, 3, true },
1027 { 0x55555, 0x110000, 6, true }, /* highStart<U+ffff with non-initialValue */
1028 { 0xcccc, 0x55555, 6, true }
1029 };
1030
1031 static const CheckRange
1032 checkRanges3[]={
1033 { 0, 9 }, /* non-zero initialValue */
1034 { 0x31, 9 },
1035 { 0xa4, 1 },
1036 { 0x3400, 9 },
1037 { 0x6789, 2 },
1038 { 0x9000, 9 },
1039 { 0xa000, 4 },
1040 { 0xabcd, 9 },
1041 { 0xbcde, 3 },
1042 { 0xcccc, 9 },
1043 { 0x110000, 6 }
1044 };
1045
1046 /* empty or single-value tries, testing highStart==0 */
1047 static const SetRange
1048 setRangesEmpty[]={
1049 { 0, 0, 0, false }, /* need some values for it to compile */
1050 };
1051
1052 static const CheckRange
1053 checkRangesEmpty[]={
1054 { 0, 3 },
1055 { 0x110000, 3 }
1056 };
1057
1058 static const SetRange
1059 setRangesSingleValue[]={
1060 { 0, 0x110000, 5, true },
1061 };
1062
1063 static const CheckRange
1064 checkRangesSingleValue[]={
1065 { 0, 3 },
1066 { 0x110000, 5 }
1067 };
1068
1069 static void
TrieTest(void)1070 TrieTest(void) {
1071 testTrieRanges("set1", false,
1072 setRanges1, UPRV_LENGTHOF(setRanges1),
1073 checkRanges1, UPRV_LENGTHOF(checkRanges1));
1074 testTrieRanges("set2-overlap", false,
1075 setRanges2, UPRV_LENGTHOF(setRanges2),
1076 checkRanges2, UPRV_LENGTHOF(checkRanges2));
1077 testTrieRanges("set3-initial-9", false,
1078 setRanges3, UPRV_LENGTHOF(setRanges3),
1079 checkRanges3, UPRV_LENGTHOF(checkRanges3));
1080 testTrieRanges("set-empty", false,
1081 setRangesEmpty, 0,
1082 checkRangesEmpty, UPRV_LENGTHOF(checkRangesEmpty));
1083 testTrieRanges("set-single-value", false,
1084 setRangesSingleValue, UPRV_LENGTHOF(setRangesSingleValue),
1085 checkRangesSingleValue, UPRV_LENGTHOF(checkRangesSingleValue));
1086
1087 testTrieRanges("set2-overlap.withClone", true,
1088 setRanges2, UPRV_LENGTHOF(setRanges2),
1089 checkRanges2, UPRV_LENGTHOF(checkRanges2));
1090 }
1091
1092 static void
EnumNewTrieForLeadSurrogateTest(void)1093 EnumNewTrieForLeadSurrogateTest(void) {
1094 static const char *const testName="enum-for-lead";
1095 UTrie2 *trie=makeTrieWithRanges(testName, false,
1096 setRanges2, UPRV_LENGTHOF(setRanges2),
1097 checkRanges2, UPRV_LENGTHOF(checkRanges2));
1098 while(trie!=NULL) {
1099 const CheckRange *checkRanges;
1100
1101 checkRanges=checkRanges2_d800+1;
1102 utrie2_enumForLeadSurrogate(trie, 0xd800,
1103 testEnumValue, testEnumRange,
1104 &checkRanges);
1105 checkRanges=checkRanges2_d87e+1;
1106 utrie2_enumForLeadSurrogate(trie, 0xd87e,
1107 testEnumValue, testEnumRange,
1108 &checkRanges);
1109 checkRanges=checkRanges2_d87f+1;
1110 utrie2_enumForLeadSurrogate(trie, 0xd87f,
1111 testEnumValue, testEnumRange,
1112 &checkRanges);
1113 checkRanges=checkRanges2_dbff+1;
1114 utrie2_enumForLeadSurrogate(trie, 0xdbff,
1115 testEnumValue, testEnumRange,
1116 &checkRanges);
1117 if(!utrie2_isFrozen(trie)) {
1118 UErrorCode errorCode=U_ZERO_ERROR;
1119 utrie2_freeze(trie, UTRIE2_16_VALUE_BITS, &errorCode);
1120 if(U_FAILURE(errorCode)) {
1121 log_err("error: utrie2_freeze(%s) failed\n", testName);
1122 utrie2_close(trie);
1123 return;
1124 }
1125 } else {
1126 utrie2_close(trie);
1127 break;
1128 }
1129 }
1130 }
1131
1132 /* test utrie2_openDummy() -------------------------------------------------- */
1133
1134 static void
dummyTest(UTrie2ValueBits valueBits)1135 dummyTest(UTrie2ValueBits valueBits) {
1136 CheckRange
1137 checkRanges[]={
1138 { -1, 0 },
1139 { 0, 0 },
1140 { 0x110000, 0 }
1141 };
1142
1143 UTrie2 *trie;
1144 UErrorCode errorCode;
1145
1146 const char *testName;
1147 uint32_t initialValue, errorValue;
1148
1149 if(valueBits==UTRIE2_16_VALUE_BITS) {
1150 testName="dummy.16";
1151 initialValue=0x313;
1152 errorValue=0xaffe;
1153 } else {
1154 testName="dummy.32";
1155 initialValue=0x01234567;
1156 errorValue=0x89abcdef;
1157 }
1158 checkRanges[0].value=errorValue;
1159 checkRanges[1].value=checkRanges[2].value=initialValue;
1160
1161 errorCode=U_ZERO_ERROR;
1162 trie=utrie2_openDummy(valueBits, initialValue, errorValue, &errorCode);
1163 if(U_FAILURE(errorCode)) {
1164 log_err("utrie2_openDummy(valueBits=%d) failed - %s\n", valueBits, u_errorName(errorCode));
1165 return;
1166 }
1167
1168 testFrozenTrie(testName, trie, valueBits, checkRanges, UPRV_LENGTHOF(checkRanges));
1169 utrie2_close(trie);
1170 }
1171
1172 static void
DummyTrieTest(void)1173 DummyTrieTest(void) {
1174 dummyTest(UTRIE2_16_VALUE_BITS);
1175 dummyTest(UTRIE2_32_VALUE_BITS);
1176 }
1177
1178 /* test builder memory management ------------------------------------------- */
1179
1180 static void
FreeBlocksTest(void)1181 FreeBlocksTest(void) {
1182 static const CheckRange
1183 checkRanges[]={
1184 { 0, 1 },
1185 { 0x740, 1 },
1186 { 0x780, 2 },
1187 { 0x880, 3 },
1188 { 0x110000, 1 }
1189 };
1190 static const char *const testName="free-blocks";
1191
1192 UTrie2 *trie;
1193 int32_t i;
1194 UErrorCode errorCode;
1195
1196 errorCode=U_ZERO_ERROR;
1197 trie=utrie2_open(1, 0xbad, &errorCode);
1198 if(U_FAILURE(errorCode)) {
1199 log_err("error: utrie2_open(%s) failed: %s\n", testName, u_errorName(errorCode));
1200 return;
1201 }
1202
1203 /*
1204 * Repeatedly set overlapping same-value ranges to stress the free-data-block management.
1205 * If it fails, it will overflow the data array.
1206 */
1207 for(i=0; i<(0x120000>>UTRIE2_SHIFT_2)/2; ++i) {
1208 utrie2_setRange32(trie, 0x740, 0x840-1, 1, true, &errorCode);
1209 utrie2_setRange32(trie, 0x780, 0x880-1, 1, true, &errorCode);
1210 utrie2_setRange32(trie, 0x740, 0x840-1, 2, true, &errorCode);
1211 utrie2_setRange32(trie, 0x780, 0x880-1, 3, true, &errorCode);
1212 }
1213 /* make blocks that will be free during compaction */
1214 utrie2_setRange32(trie, 0x1000, 0x3000-1, 2, true, &errorCode);
1215 utrie2_setRange32(trie, 0x2000, 0x4000-1, 3, true, &errorCode);
1216 utrie2_setRange32(trie, 0x1000, 0x4000-1, 1, true, &errorCode);
1217 /* set some values for lead surrogate code units */
1218 utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xd800, 90, &errorCode);
1219 utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xd999, 94, &errorCode);
1220 utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xdbff, 99, &errorCode);
1221 if(U_FAILURE(errorCode)) {
1222 log_err("error: setting lots of ranges into a trie (%s) failed - %s\n",
1223 testName, u_errorName(errorCode));
1224 utrie2_close(trie);
1225 return;
1226 }
1227
1228 trie=testTrieSerializeAllValueBits(testName, trie, false,
1229 checkRanges, UPRV_LENGTHOF(checkRanges));
1230 utrie2_close(trie);
1231 }
1232
1233 static void
GrowDataArrayTest(void)1234 GrowDataArrayTest(void) {
1235 static const CheckRange
1236 checkRanges[]={
1237 { 0, 1 },
1238 { 0x720, 2 },
1239 { 0x7a0, 3 },
1240 { 0x8a0, 4 },
1241 { 0x110000, 5 }
1242 };
1243 static const char *const testName="grow-data";
1244
1245 UTrie2 *trie;
1246 int32_t i;
1247 UErrorCode errorCode;
1248
1249 errorCode=U_ZERO_ERROR;
1250 trie=utrie2_open(1, 0xbad, &errorCode);
1251 if(U_FAILURE(errorCode)) {
1252 log_err("error: utrie2_open(%s) failed: %s\n", testName, u_errorName(errorCode));
1253 return;
1254 }
1255
1256 /*
1257 * Use utrie2_set32() not utrie2_setRange32() to write non-initialValue-data.
1258 * Should grow/reallocate the data array to a sufficient length.
1259 */
1260 for(i=0; i<0x1000; ++i) {
1261 utrie2_set32(trie, i, 2, &errorCode);
1262 }
1263 for(i=0x720; i<0x1100; ++i) { /* some overlap */
1264 utrie2_set32(trie, i, 3, &errorCode);
1265 }
1266 for(i=0x7a0; i<0x900; ++i) {
1267 utrie2_set32(trie, i, 4, &errorCode);
1268 }
1269 for(i=0x8a0; i<0x110000; ++i) {
1270 utrie2_set32(trie, i, 5, &errorCode);
1271 }
1272 for(i=0xd800; i<0xdc00; ++i) {
1273 utrie2_set32ForLeadSurrogateCodeUnit(trie, i, 1, &errorCode);
1274 }
1275 /* set some values for lead surrogate code units */
1276 utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xd800, 90, &errorCode);
1277 utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xd999, 94, &errorCode);
1278 utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xdbff, 99, &errorCode);
1279 if(U_FAILURE(errorCode)) {
1280 log_err("error: setting lots of values into a trie (%s) failed - %s\n",
1281 testName, u_errorName(errorCode));
1282 utrie2_close(trie);
1283 return;
1284 }
1285
1286 trie=testTrieSerializeAllValueBits(testName, trie, false,
1287 checkRanges, UPRV_LENGTHOF(checkRanges));
1288 utrie2_close(trie);
1289 }
1290
1291 /* versions 1 and 2 --------------------------------------------------------- */
1292
1293 static UNewTrie *
makeNewTrie1WithRanges(const char * testName,const SetRange setRanges[],int32_t countSetRanges,const CheckRange checkRanges[],int32_t countCheckRanges)1294 makeNewTrie1WithRanges(const char *testName,
1295 const SetRange setRanges[], int32_t countSetRanges,
1296 const CheckRange checkRanges[], int32_t countCheckRanges) {
1297 UNewTrie *newTrie;
1298 uint32_t initialValue, errorValue;
1299 uint32_t value;
1300 UChar32 start, limit;
1301 int32_t i;
1302 UErrorCode errorCode;
1303 UBool overwrite, ok;
1304
1305 log_verbose("\ntesting Trie '%s'\n", testName);
1306 errorCode=U_ZERO_ERROR;
1307 getSpecialValues(checkRanges, countCheckRanges, &initialValue, &errorValue);
1308 newTrie=utrie_open(NULL, NULL, 2000,
1309 initialValue, initialValue,
1310 false);
1311 if(U_FAILURE(errorCode)) {
1312 log_err("error: utrie_open(%s) failed: %s\n", testName, u_errorName(errorCode));
1313 return NULL;
1314 }
1315
1316 /* set values from setRanges[] */
1317 ok=true;
1318 for(i=0; i<countSetRanges; ++i) {
1319 start=setRanges[i].start;
1320 limit=setRanges[i].limit;
1321 value=setRanges[i].value;
1322 overwrite=setRanges[i].overwrite;
1323 if((limit-start)==1 && overwrite) {
1324 ok&=utrie_set32(newTrie, start, value);
1325 } else {
1326 ok&=utrie_setRange32(newTrie, start, limit, value, overwrite);
1327 }
1328 }
1329 if(ok) {
1330 return newTrie;
1331 } else {
1332 log_err("error: setting values into a trie1 (%s) failed\n", testName);
1333 utrie_close(newTrie);
1334 return NULL;
1335 }
1336 }
1337
1338 static void
testTrie2FromTrie1(const char * testName,const SetRange setRanges[],int32_t countSetRanges,const CheckRange checkRanges[],int32_t countCheckRanges)1339 testTrie2FromTrie1(const char *testName,
1340 const SetRange setRanges[], int32_t countSetRanges,
1341 const CheckRange checkRanges[], int32_t countCheckRanges) {
1342 uint32_t memory1_16[3000], memory1_32[3000];
1343 int32_t length16, length32;
1344 UChar lead;
1345
1346 char name[40];
1347
1348 UNewTrie *newTrie1_16, *newTrie1_32;
1349 UTrie trie1_16, trie1_32;
1350 UTrie2 *trie2;
1351 uint32_t initialValue, errorValue;
1352 UErrorCode errorCode;
1353
1354 newTrie1_16=makeNewTrie1WithRanges(testName,
1355 setRanges, countSetRanges,
1356 checkRanges, countCheckRanges);
1357 if(newTrie1_16==NULL) {
1358 return;
1359 }
1360 newTrie1_32=utrie_clone(NULL, newTrie1_16, NULL, 0);
1361 if(newTrie1_32==NULL) {
1362 utrie_close(newTrie1_16);
1363 return;
1364 }
1365 errorCode=U_ZERO_ERROR;
1366 length16=utrie_serialize(newTrie1_16, memory1_16, sizeof(memory1_16),
1367 NULL, true, &errorCode);
1368 length32=utrie_serialize(newTrie1_32, memory1_32, sizeof(memory1_32),
1369 NULL, false, &errorCode);
1370 utrie_unserialize(&trie1_16, memory1_16, length16, &errorCode);
1371 utrie_unserialize(&trie1_32, memory1_32, length32, &errorCode);
1372 utrie_close(newTrie1_16);
1373 utrie_close(newTrie1_32);
1374 if(U_FAILURE(errorCode)) {
1375 log_err("error: utrie_serialize or unserialize(%s) failed: %s\n",
1376 testName, u_errorName(errorCode));
1377 return;
1378 }
1379
1380 getSpecialValues(checkRanges, countCheckRanges, &initialValue, &errorValue);
1381
1382 uprv_strcpy(name, testName);
1383 uprv_strcat(name, ".16");
1384 trie2=utrie2_fromUTrie(&trie1_16, errorValue, &errorCode);
1385 if(U_SUCCESS(errorCode)) {
1386 testFrozenTrie(name, trie2, UTRIE2_16_VALUE_BITS, checkRanges, countCheckRanges);
1387 for(lead=0xd800; lead<0xdc00; ++lead) {
1388 uint32_t value1, value2;
1389 value1=UTRIE_GET16_FROM_LEAD(&trie1_16, lead);
1390 value2=UTRIE2_GET16_FROM_U16_SINGLE_LEAD(trie2, lead);
1391 if(value1!=value2) {
1392 log_err("error: utrie2_fromUTrie(%s) wrong value %ld!=%ld "
1393 "from lead surrogate code unit U+%04lx\n",
1394 name, (long)value2, (long)value1, (long)lead);
1395 break;
1396 }
1397 }
1398 }
1399 utrie2_close(trie2);
1400
1401 uprv_strcpy(name, testName);
1402 uprv_strcat(name, ".32");
1403 trie2=utrie2_fromUTrie(&trie1_32, errorValue, &errorCode);
1404 if(U_SUCCESS(errorCode)) {
1405 testFrozenTrie(name, trie2, UTRIE2_32_VALUE_BITS, checkRanges, countCheckRanges);
1406 for(lead=0xd800; lead<0xdc00; ++lead) {
1407 uint32_t value1, value2;
1408 value1=UTRIE_GET32_FROM_LEAD(&trie1_32, lead);
1409 value2=UTRIE2_GET32_FROM_U16_SINGLE_LEAD(trie2, lead);
1410 if(value1!=value2) {
1411 log_err("error: utrie2_fromUTrie(%s) wrong value %ld!=%ld "
1412 "from lead surrogate code unit U+%04lx\n",
1413 name, (long)value2, (long)value1, (long)lead);
1414 break;
1415 }
1416 }
1417 }
1418 utrie2_close(trie2);
1419 }
1420
1421 static void
Trie12ConversionTest(void)1422 Trie12ConversionTest(void) {
1423 testTrie2FromTrie1("trie1->trie2",
1424 setRanges2, UPRV_LENGTHOF(setRanges2),
1425 checkRanges2, UPRV_LENGTHOF(checkRanges2));
1426 }
1427
1428 void
addTrie2Test(TestNode ** root)1429 addTrie2Test(TestNode** root) {
1430 addTest(root, &TrieTest, "tsutil/trie2test/TrieTest");
1431 addTest(root, &EnumNewTrieForLeadSurrogateTest,
1432 "tsutil/trie2test/EnumNewTrieForLeadSurrogateTest");
1433 addTest(root, &DummyTrieTest, "tsutil/trie2test/DummyTrieTest");
1434 addTest(root, &FreeBlocksTest, "tsutil/trie2test/FreeBlocksTest");
1435 addTest(root, &GrowDataArrayTest, "tsutil/trie2test/GrowDataArrayTest");
1436 addTest(root, &Trie12ConversionTest, "tsutil/trie2test/Trie12ConversionTest");
1437 }
1438