1 // © 2017 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3
4 // ucptrietest.c (modified from trie2test.c)
5 // created: 2017dec29 Markus W. Scherer
6
7 #include <stdio.h>
8 #include "unicode/utypes.h"
9 #include "unicode/ucptrie.h"
10 #include "unicode/umutablecptrie.h"
11 #include "unicode/utf.h"
12 #include "unicode/utf16.h"
13 #include "unicode/utf8.h"
14 #include "uassert.h"
15 #include "ucptrie_impl.h"
16 #include "utrie.h"
17 #include "cstring.h"
18 #include "cmemory.h"
19 #include "udataswp.h"
20 #include "cintltst.h"
21
22 void addUCPTrieTest(TestNode** root);
23
24 /* Values for setting possibly overlapping, out-of-order ranges of values */
25 typedef struct SetRange {
26 UChar32 start, limit;
27 uint32_t value;
28 } SetRange;
29
30 /*
31 * Values for testing:
32 * value is set from the previous boundary's limit to before
33 * this boundary's limit
34 *
35 * There must be an entry with limit 0 and the intialValue.
36 * It may be preceded by an entry with negative limit and the errorValue.
37 */
38 typedef struct CheckRange {
39 UChar32 limit;
40 uint32_t value;
41 } CheckRange;
42
43 static int32_t
skipSpecialValues(const CheckRange checkRanges[],int32_t countCheckRanges)44 skipSpecialValues(const CheckRange checkRanges[], int32_t countCheckRanges) {
45 int32_t i;
46 for(i=0; i<countCheckRanges && checkRanges[i].limit<=0; ++i) {}
47 return i;
48 }
49
50 static int32_t
getSpecialValues(const CheckRange checkRanges[],int32_t countCheckRanges,uint32_t * pInitialValue,uint32_t * pErrorValue)51 getSpecialValues(const CheckRange checkRanges[], int32_t countCheckRanges,
52 uint32_t *pInitialValue, uint32_t *pErrorValue) {
53 int32_t i=0;
54 if(i<countCheckRanges && checkRanges[i].limit<0) {
55 *pErrorValue=checkRanges[i++].value;
56 } else {
57 *pErrorValue=0xad;
58 }
59 if(i<countCheckRanges && checkRanges[i].limit==0) {
60 *pInitialValue=checkRanges[i++].value;
61 } else {
62 *pInitialValue=0;
63 }
64 return i;
65 }
66
67 /* ucptrie_enum() callback, modifies a value */
68 static uint32_t U_CALLCONV
testFilter(const void * context,uint32_t value)69 testFilter(const void *context, uint32_t value) {
70 return value ^ 0x5555;
71 }
72
73 static UBool
doCheckRange(const char * name,const char * variant,UChar32 start,UChar32 end,uint32_t value,UChar32 expEnd,uint32_t expValue)74 doCheckRange(const char *name, const char *variant,
75 UChar32 start, UChar32 end, uint32_t value,
76 UChar32 expEnd, uint32_t expValue) {
77 if (end < 0) {
78 if (expEnd >= 0) {
79 log_err("error: %s getRanges (%s) fails to deliver range [U+%04lx..U+%04lx].0x%lx\n",
80 name, variant, (long)start, (long)expEnd, (long)expValue);
81 }
82 return FALSE;
83 }
84 if (expEnd < 0) {
85 log_err("error: %s getRanges (%s) delivers unexpected range [U+%04lx..U+%04lx].0x%lx\n",
86 name, variant, (long)start, (long)end, (long)value);
87 return FALSE;
88 }
89 if (end != expEnd || value != expValue) {
90 log_err("error: %s getRanges (%s) delivers wrong range [U+%04lx..U+%04lx].0x%lx "
91 "instead of [U+%04lx..U+%04lx].0x%lx\n",
92 name, variant, (long)start, (long)end, (long)value,
93 (long)start, (long)expEnd, (long)expValue);
94 return FALSE;
95 }
96 return TRUE;
97 }
98
99 // Test iteration starting from various UTF-8/16 and trie structure boundaries.
100 // Also test starting partway through lead & trail surrogates for fixed-surrogate-value options,
101 // and partway through supplementary code points.
102 static UChar32 iterStarts[] = {
103 0, 0x7f, 0x80, 0x7ff, 0x800, 0xfff, 0x1000,
104 0xd7ff, 0xd800, 0xd888, 0xdddd, 0xdfff, 0xe000,
105 0xffff, 0x10000, 0x12345, 0x10ffff, 0x110000
106 };
107
108 static void
testTrieGetRanges(const char * testName,const UCPTrie * trie,const UMutableCPTrie * mutableTrie,UCPMapRangeOption option,uint32_t surrValue,const CheckRange checkRanges[],int32_t countCheckRanges)109 testTrieGetRanges(const char *testName, const UCPTrie *trie, const UMutableCPTrie *mutableTrie,
110 UCPMapRangeOption option, uint32_t surrValue,
111 const CheckRange checkRanges[], int32_t countCheckRanges) {
112 const char *const typeName = trie == NULL ? "mutableTrie" : "trie";
113 const char *const optionName = option == UCPMAP_RANGE_NORMAL ? "normal" :
114 option == UCPMAP_RANGE_FIXED_LEAD_SURROGATES ? "fixedLeadSurr" : "fixedAllSurr";
115 char name[80];
116 int32_t s;
117 for (s = 0; s < UPRV_LENGTHOF(iterStarts); ++s) {
118 UChar32 start = iterStarts[s];
119 int32_t i, i0;
120 UChar32 end, expEnd;
121 uint32_t value, expValue;
122 // No need to go from each iteration start to the very end.
123 int32_t innerLoopCount;
124
125 sprintf(name, "%s/%s(%s) min=U+%04lx", typeName, optionName, testName, (long)start);
126
127 // Skip over special values and low ranges.
128 for (i = 0; i < countCheckRanges && checkRanges[i].limit <= start; ++i) {}
129 i0 = i;
130 // without value handler
131 for (innerLoopCount = 0;; ++i, start = end + 1) {
132 if (i < countCheckRanges) {
133 expEnd = checkRanges[i].limit - 1;
134 expValue = checkRanges[i].value;
135 } else {
136 expEnd = -1;
137 expValue = value = 0x5005;
138 }
139 end = trie != NULL ?
140 ucptrie_getRange(trie, start, option, surrValue, NULL, NULL, &value) :
141 umutablecptrie_getRange(mutableTrie, start, option, surrValue, NULL, NULL, &value);
142 if (!doCheckRange(name, "without value handler", start, end, value, expEnd, expValue)) {
143 break;
144 }
145 if (s != 0 && ++innerLoopCount == 5) { break; }
146 }
147 // with value handler
148 for (i = i0, start = iterStarts[s], innerLoopCount = 0;; ++i, start = end + 1) {
149 if (i < countCheckRanges) {
150 expEnd = checkRanges[i].limit - 1;
151 expValue = checkRanges[i].value ^ 0x5555;
152 } else {
153 expEnd = -1;
154 expValue = value = 0x5005;
155 }
156 end = trie != NULL ?
157 ucptrie_getRange(trie, start, option, surrValue ^ 0x5555, testFilter, NULL, &value) :
158 umutablecptrie_getRange(mutableTrie, start, option, surrValue ^ 0x5555,
159 testFilter, NULL, &value);
160 if (!doCheckRange(name, "with value handler", start, end, value, expEnd, expValue)) {
161 break;
162 }
163 if (s != 0 && ++innerLoopCount == 5) { break; }
164 }
165 // without value
166 for (i = i0, start = iterStarts[s], innerLoopCount = 0;; ++i, start = end + 1) {
167 if (i < countCheckRanges) {
168 expEnd = checkRanges[i].limit - 1;
169 } else {
170 expEnd = -1;
171 }
172 end = trie != NULL ?
173 ucptrie_getRange(trie, start, option, surrValue, NULL, NULL, NULL) :
174 umutablecptrie_getRange(mutableTrie, start, option, surrValue, NULL, NULL, NULL);
175 if (!doCheckRange(name, "without value", start, end, 0, expEnd, 0)) {
176 break;
177 }
178 if (s != 0 && ++innerLoopCount == 5) { break; }
179 }
180 }
181 }
182
183 static void
testTrieGetters(const char * testName,const UCPTrie * trie,UCPTrieType type,UCPTrieValueWidth valueWidth,const CheckRange checkRanges[],int32_t countCheckRanges)184 testTrieGetters(const char *testName, const UCPTrie *trie,
185 UCPTrieType type, UCPTrieValueWidth valueWidth,
186 const CheckRange checkRanges[], int32_t countCheckRanges) {
187 uint32_t initialValue, errorValue;
188 uint32_t value, value2;
189 UChar32 start, limit;
190 int32_t i, countSpecials;
191 int32_t countErrors=0;
192
193 const char *const typeName = "trie";
194
195 countSpecials=getSpecialValues(checkRanges, countCheckRanges, &initialValue, &errorValue);
196
197 start=0;
198 for(i=countSpecials; i<countCheckRanges; ++i) {
199 limit=checkRanges[i].limit;
200 value=checkRanges[i].value;
201
202 while(start<limit) {
203 if (start <= 0x7f) {
204 if (valueWidth == UCPTRIE_VALUE_BITS_16) {
205 value2 = UCPTRIE_ASCII_GET(trie, UCPTRIE_16, start);
206 } else if (valueWidth == UCPTRIE_VALUE_BITS_32) {
207 value2 = UCPTRIE_ASCII_GET(trie, UCPTRIE_32, start);
208 } else {
209 value2 = UCPTRIE_ASCII_GET(trie, UCPTRIE_8, start);
210 }
211 if (value != value2) {
212 log_err("error: %s(%s).fromASCII(U+%04lx)==0x%lx instead of 0x%lx\n",
213 typeName, testName, (long)start, (long)value2, (long)value);
214 ++countErrors;
215 }
216 }
217 if (type == UCPTRIE_TYPE_FAST) {
218 if(start<=0xffff) {
219 if(valueWidth==UCPTRIE_VALUE_BITS_16) {
220 value2=UCPTRIE_FAST_BMP_GET(trie, UCPTRIE_16, start);
221 } else if(valueWidth==UCPTRIE_VALUE_BITS_32) {
222 value2=UCPTRIE_FAST_BMP_GET(trie, UCPTRIE_32, start);
223 } else {
224 value2=UCPTRIE_FAST_BMP_GET(trie, UCPTRIE_8, start);
225 }
226 if(value!=value2) {
227 log_err("error: %s(%s).fromBMP(U+%04lx)==0x%lx instead of 0x%lx\n",
228 typeName, testName, (long)start, (long)value2, (long)value);
229 ++countErrors;
230 }
231 } else {
232 if(valueWidth==UCPTRIE_VALUE_BITS_16) {
233 value2 = UCPTRIE_FAST_SUPP_GET(trie, UCPTRIE_16, start);
234 } else if(valueWidth==UCPTRIE_VALUE_BITS_32) {
235 value2 = UCPTRIE_FAST_SUPP_GET(trie, UCPTRIE_32, start);
236 } else {
237 value2 = UCPTRIE_FAST_SUPP_GET(trie, UCPTRIE_8, start);
238 }
239 if(value!=value2) {
240 log_err("error: %s(%s).fromSupp(U+%04lx)==0x%lx instead of 0x%lx\n",
241 typeName, testName, (long)start, (long)value2, (long)value);
242 ++countErrors;
243 }
244 }
245 if(valueWidth==UCPTRIE_VALUE_BITS_16) {
246 value2 = UCPTRIE_FAST_GET(trie, UCPTRIE_16, start);
247 } else if(valueWidth==UCPTRIE_VALUE_BITS_32) {
248 value2 = UCPTRIE_FAST_GET(trie, UCPTRIE_32, start);
249 } else {
250 value2 = UCPTRIE_FAST_GET(trie, UCPTRIE_8, start);
251 }
252 } else {
253 if(valueWidth==UCPTRIE_VALUE_BITS_16) {
254 value2 = UCPTRIE_SMALL_GET(trie, UCPTRIE_16, start);
255 } else if(valueWidth==UCPTRIE_VALUE_BITS_32) {
256 value2 = UCPTRIE_SMALL_GET(trie, UCPTRIE_32, start);
257 } else {
258 value2 = UCPTRIE_SMALL_GET(trie, UCPTRIE_8, start);
259 }
260 }
261 if(value!=value2) {
262 log_err("error: %s(%s).get(U+%04lx)==0x%lx instead of 0x%lx\n",
263 typeName, testName, (long)start, (long)value2, (long)value);
264 ++countErrors;
265 }
266 value2=ucptrie_get(trie, start);
267 if(value!=value2) {
268 log_err("error: %s(%s).get(U+%04lx)==0x%lx instead of 0x%lx\n",
269 typeName, testName, (long)start, (long)value2, (long)value);
270 ++countErrors;
271 }
272 ++start;
273 if(countErrors>10) {
274 return;
275 }
276 }
277 }
278
279 /* test linear ASCII range from the data array pointer (access to "internal" field) */
280 start=0;
281 for(i=countSpecials; i<countCheckRanges && start<=0x7f; ++i) {
282 limit=checkRanges[i].limit;
283 value=checkRanges[i].value;
284
285 while(start<limit && start<=0x7f) {
286 if(valueWidth==UCPTRIE_VALUE_BITS_16) {
287 value2=trie->data.ptr16[start];
288 } else if(valueWidth==UCPTRIE_VALUE_BITS_32) {
289 value2=trie->data.ptr32[start];
290 } else {
291 value2=trie->data.ptr8[start];
292 }
293 if(value!=value2) {
294 log_err("error: %s(%s).asciiData[U+%04lx]==0x%lx instead of 0x%lx\n",
295 typeName, testName, (long)start, (long)value2, (long)value);
296 ++countErrors;
297 }
298 ++start;
299 if(countErrors>10) {
300 return;
301 }
302 }
303 }
304
305 /* test errorValue */
306 if (type == UCPTRIE_TYPE_FAST) {
307 if(valueWidth==UCPTRIE_VALUE_BITS_16) {
308 value = UCPTRIE_FAST_GET(trie, UCPTRIE_16, -1);
309 value2 = UCPTRIE_FAST_GET(trie, UCPTRIE_16, 0x110000);
310 } else if(valueWidth==UCPTRIE_VALUE_BITS_32) {
311 value = UCPTRIE_FAST_GET(trie, UCPTRIE_32, -1);
312 value2 = UCPTRIE_FAST_GET(trie, UCPTRIE_32, 0x110000);
313 } else {
314 value = UCPTRIE_FAST_GET(trie, UCPTRIE_8, -1);
315 value2 = UCPTRIE_FAST_GET(trie, UCPTRIE_8, 0x110000);
316 }
317 } else {
318 if(valueWidth==UCPTRIE_VALUE_BITS_16) {
319 value = UCPTRIE_SMALL_GET(trie, UCPTRIE_16, -1);
320 value2 = UCPTRIE_SMALL_GET(trie, UCPTRIE_16, 0x110000);
321 } else if(valueWidth==UCPTRIE_VALUE_BITS_32) {
322 value = UCPTRIE_SMALL_GET(trie, UCPTRIE_32, -1);
323 value2 = UCPTRIE_SMALL_GET(trie, UCPTRIE_32, 0x110000);
324 } else {
325 value = UCPTRIE_SMALL_GET(trie, UCPTRIE_8, -1);
326 value2 = UCPTRIE_SMALL_GET(trie, UCPTRIE_8, 0x110000);
327 }
328 }
329 if(value!=errorValue || value2!=errorValue) {
330 log_err("error: %s(%s).get(out of range) != errorValue\n",
331 typeName, testName);
332 }
333 value=ucptrie_get(trie, -1);
334 value2=ucptrie_get(trie, 0x110000);
335 if(value!=errorValue || value2!=errorValue) {
336 log_err("error: %s(%s).get(out of range) != errorValue\n",
337 typeName, testName);
338 }
339 }
340
341 static void
testBuilderGetters(const char * testName,const UMutableCPTrie * mutableTrie,const CheckRange checkRanges[],int32_t countCheckRanges)342 testBuilderGetters(const char *testName, const UMutableCPTrie *mutableTrie,
343 const CheckRange checkRanges[], int32_t countCheckRanges) {
344 uint32_t initialValue, errorValue;
345 uint32_t value, value2;
346 UChar32 start, limit;
347 int32_t i, countSpecials;
348 int32_t countErrors=0;
349
350 const char *const typeName = "mutableTrie";
351
352 countSpecials=getSpecialValues(checkRanges, countCheckRanges, &initialValue, &errorValue);
353
354 start=0;
355 for(i=countSpecials; i<countCheckRanges; ++i) {
356 limit=checkRanges[i].limit;
357 value=checkRanges[i].value;
358
359 while(start<limit) {
360 value2=umutablecptrie_get(mutableTrie, start);
361 if(value!=value2) {
362 log_err("error: %s(%s).get(U+%04lx)==0x%lx instead of 0x%lx\n",
363 typeName, testName, (long)start, (long)value2, (long)value);
364 ++countErrors;
365 }
366 ++start;
367 if(countErrors>10) {
368 return;
369 }
370 }
371 }
372
373 /* test errorValue */
374 value=umutablecptrie_get(mutableTrie, -1);
375 value2=umutablecptrie_get(mutableTrie, 0x110000);
376 if(value!=errorValue || value2!=errorValue) {
377 log_err("error: %s(%s).get(out of range) != errorValue\n",
378 typeName, testName);
379 }
380 }
381
382 #define ACCIDENTAL_SURROGATE_PAIR(s, length, cp) (length > 0 && U16_IS_LEAD(s[length-1]) && U_IS_TRAIL(cp))
383
384 static void
testTrieUTF16(const char * testName,const UCPTrie * trie,UCPTrieValueWidth valueWidth,const CheckRange checkRanges[],int32_t countCheckRanges)385 testTrieUTF16(const char *testName,
386 const UCPTrie *trie, UCPTrieValueWidth valueWidth,
387 const CheckRange checkRanges[], int32_t countCheckRanges) {
388 UChar s[30000];
389 uint32_t values[16000];
390
391 const UChar *p, *limit;
392
393 uint32_t errorValue = ucptrie_get(trie, -1);
394 uint32_t value, expected;
395 UChar32 prevCP, c, c2;
396 int32_t i, length, sIndex, countValues;
397
398 /* write a string */
399 prevCP=0;
400 length=countValues=0;
401 for(i=skipSpecialValues(checkRanges, countCheckRanges); i<countCheckRanges; ++i) {
402 value=checkRanges[i].value;
403 /* write three code points */
404 if(!ACCIDENTAL_SURROGATE_PAIR(s, length, prevCP)) {
405 U16_APPEND_UNSAFE(s, length, prevCP); /* start of the range */
406 values[countValues++]=value;
407 }
408 U_ASSERT(length < UPRV_LENGTHOF(s) && countValues < UPRV_LENGTHOF(values));
409 c=checkRanges[i].limit;
410 prevCP=(prevCP+c)/2; /* middle of the range */
411 if(!ACCIDENTAL_SURROGATE_PAIR(s, length, prevCP)) {
412 U16_APPEND_UNSAFE(s, length, prevCP);
413 values[countValues++]=value;
414 }
415 prevCP=c;
416 --c; /* end of the range */
417 if(!ACCIDENTAL_SURROGATE_PAIR(s, length, c)) {
418 U16_APPEND_UNSAFE(s, length, c);
419 values[countValues++]=value;
420 }
421 }
422 limit=s+length;
423 if(length>UPRV_LENGTHOF(s)) {
424 log_err("UTF-16 test string length %d > capacity %d\n", (int)length, (int)UPRV_LENGTHOF(s));
425 return;
426 }
427 if(countValues>UPRV_LENGTHOF(values)) {
428 log_err("UTF-16 test values length %d > capacity %d\n", (int)countValues, (int)UPRV_LENGTHOF(values));
429 return;
430 }
431
432 /* try forward */
433 p=s;
434 i=0;
435 while(p<limit) {
436 sIndex=(int32_t)(p-s);
437 U16_NEXT(s, sIndex, length, c2);
438 c=0x33;
439 if(valueWidth==UCPTRIE_VALUE_BITS_16) {
440 UCPTRIE_FAST_U16_NEXT(trie, UCPTRIE_16, p, limit, c, value);
441 } else if(valueWidth==UCPTRIE_VALUE_BITS_32) {
442 UCPTRIE_FAST_U16_NEXT(trie, UCPTRIE_32, p, limit, c, value);
443 } else {
444 UCPTRIE_FAST_U16_NEXT(trie, UCPTRIE_8, p, limit, c, value);
445 }
446 expected = U_IS_SURROGATE(c) ? errorValue : values[i];
447 if(value!=expected) {
448 log_err("error: wrong value from UCPTRIE_NEXT(%s)(U+%04lx): 0x%lx instead of 0x%lx\n",
449 testName, (long)c, (long)value, (long)expected);
450 }
451 if(c!=c2) {
452 log_err("error: wrong code point from UCPTRIE_NEXT(%s): U+%04lx != U+%04lx\n",
453 testName, (long)c, (long)c2);
454 continue;
455 }
456 ++i;
457 }
458
459 /* try backward */
460 p=limit;
461 i=countValues;
462 while(s<p) {
463 --i;
464 sIndex=(int32_t)(p-s);
465 U16_PREV(s, 0, sIndex, c2);
466 c=0x33;
467 if(valueWidth==UCPTRIE_VALUE_BITS_16) {
468 UCPTRIE_FAST_U16_PREV(trie, UCPTRIE_16, s, p, c, value);
469 } else if(valueWidth==UCPTRIE_VALUE_BITS_32) {
470 UCPTRIE_FAST_U16_PREV(trie, UCPTRIE_32, s, p, c, value);
471 } else {
472 UCPTRIE_FAST_U16_PREV(trie, UCPTRIE_8, s, p, c, value);
473 }
474 expected = U_IS_SURROGATE(c) ? errorValue : values[i];
475 if(value!=expected) {
476 log_err("error: wrong value from UCPTRIE_PREV(%s)(U+%04lx): 0x%lx instead of 0x%lx\n",
477 testName, (long)c, (long)value, (long)expected);
478 }
479 if(c!=c2) {
480 log_err("error: wrong code point from UCPTRIE_PREV(%s): U+%04lx != U+%04lx\n",
481 testName, c, c2);
482 }
483 }
484 }
485
486 static void
testTrieUTF8(const char * testName,const UCPTrie * trie,UCPTrieValueWidth valueWidth,const CheckRange checkRanges[],int32_t countCheckRanges)487 testTrieUTF8(const char *testName,
488 const UCPTrie *trie, UCPTrieValueWidth valueWidth,
489 const CheckRange checkRanges[], int32_t countCheckRanges) {
490 // Note: The byte sequence comments refer to the original UTF-8 definition.
491 // Starting with ICU 60, any sequence that is not a prefix of a valid one
492 // is treated as multiple single-byte errors.
493 // For testing, we only rely on U8_... and UCPTrie UTF-8 macros
494 // iterating consistently.
495 static const uint8_t illegal[]={
496 0xc0, 0x80, /* non-shortest U+0000 */
497 0xc1, 0xbf, /* non-shortest U+007f */
498 0xc2, /* truncated */
499 0xe0, 0x90, 0x80, /* non-shortest U+0400 */
500 0xe0, 0xa0, /* truncated */
501 0xed, 0xa0, 0x80, /* lead surrogate U+d800 */
502 0xed, 0xbf, 0xbf, /* trail surrogate U+dfff */
503 0xf0, 0x8f, 0xbf, 0xbf, /* non-shortest U+ffff */
504 0xf0, 0x90, 0x80, /* truncated */
505 0xf4, 0x90, 0x80, 0x80, /* beyond-Unicode U+110000 */
506 0xf8, 0x80, 0x80, 0x80, /* truncated */
507 0xf8, 0x80, 0x80, 0x80, 0x80, /* 5-byte UTF-8 */
508 0xfd, 0xbf, 0xbf, 0xbf, 0xbf, /* truncated */
509 0xfd, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, /* 6-byte UTF-8 */
510 0xfe,
511 0xff
512 };
513 uint8_t s[60000];
514 uint32_t values[16000];
515
516 const uint8_t *p, *limit;
517
518 uint32_t initialValue, errorValue;
519 uint32_t value, expectedBytes, actualBytes;
520 UChar32 prevCP, c;
521 int32_t i, countSpecials, length, countValues;
522 int32_t prev8, i8;
523
524 countSpecials=getSpecialValues(checkRanges, countCheckRanges, &initialValue, &errorValue);
525
526 /* write a string */
527 prevCP=0;
528 length=countValues=0;
529 /* first a couple of trail bytes in lead position */
530 s[length++]=0x80;
531 values[countValues++]=errorValue;
532 s[length++]=0xbf;
533 values[countValues++]=errorValue;
534 prev8=i8=0;
535 for(i=countSpecials; i<countCheckRanges; ++i) {
536 value=checkRanges[i].value;
537 /* write three legal (or surrogate) code points */
538 U8_APPEND_UNSAFE(s, length, prevCP); /* start of the range */
539 if(U_IS_SURROGATE(prevCP)) {
540 // A surrogate byte sequence counts as 3 single-byte errors.
541 values[countValues++]=errorValue;
542 values[countValues++]=errorValue;
543 values[countValues++]=errorValue;
544 } else {
545 values[countValues++]=value;
546 }
547 U_ASSERT(length < UPRV_LENGTHOF(s) && countValues < UPRV_LENGTHOF(values));
548 c=checkRanges[i].limit;
549 prevCP=(prevCP+c)/2; /* middle of the range */
550 U8_APPEND_UNSAFE(s, length, prevCP);
551 if(U_IS_SURROGATE(prevCP)) {
552 // A surrogate byte sequence counts as 3 single-byte errors.
553 values[countValues++]=errorValue;
554 values[countValues++]=errorValue;
555 values[countValues++]=errorValue;
556 } else {
557 values[countValues++]=value;
558 }
559 prevCP=c;
560 --c; /* end of the range */
561 U8_APPEND_UNSAFE(s, length, c);
562 if(U_IS_SURROGATE(c)) {
563 // A surrogate byte sequence counts as 3 single-byte errors.
564 values[countValues++]=errorValue;
565 values[countValues++]=errorValue;
566 values[countValues++]=errorValue;
567 } else {
568 values[countValues++]=value;
569 }
570 /* write an illegal byte sequence */
571 if(i8<sizeof(illegal)) {
572 U8_FWD_1(illegal, i8, sizeof(illegal));
573 while(prev8<i8) {
574 s[length++]=illegal[prev8++];
575 }
576 values[countValues++]=errorValue;
577 }
578 }
579 /* write the remaining illegal byte sequences */
580 while(i8<sizeof(illegal)) {
581 U8_FWD_1(illegal, i8, sizeof(illegal));
582 while(prev8<i8) {
583 s[length++]=illegal[prev8++];
584 }
585 values[countValues++]=errorValue;
586 }
587 limit=s+length;
588 if(length>UPRV_LENGTHOF(s)) {
589 log_err("UTF-8 test string length %d > capacity %d\n", (int)length, (int)UPRV_LENGTHOF(s));
590 return;
591 }
592 if(countValues>UPRV_LENGTHOF(values)) {
593 log_err("UTF-8 test values length %d > capacity %d\n", (int)countValues, (int)UPRV_LENGTHOF(values));
594 return;
595 }
596
597 /* try forward */
598 p=s;
599 i=0;
600 while(p<limit) {
601 prev8=i8=(int32_t)(p-s);
602 U8_NEXT(s, i8, length, c);
603 if(valueWidth==UCPTRIE_VALUE_BITS_16) {
604 UCPTRIE_FAST_U8_NEXT(trie, UCPTRIE_16, p, limit, value);
605 } else if(valueWidth==UCPTRIE_VALUE_BITS_32) {
606 UCPTRIE_FAST_U8_NEXT(trie, UCPTRIE_32, p, limit, value);
607 } else {
608 UCPTRIE_FAST_U8_NEXT(trie, UCPTRIE_8, p, limit, value);
609 }
610 expectedBytes=0;
611 if(value!=values[i] || i8!=(p-s)) {
612 int32_t k=prev8;
613 while(k<i8) {
614 expectedBytes=(expectedBytes<<8)|s[k++];
615 }
616 }
617 if(i8==(p-s)) {
618 actualBytes=expectedBytes;
619 } else {
620 actualBytes=0;
621 int32_t k=prev8;
622 while(k<(p-s)) {
623 actualBytes=(actualBytes<<8)|s[k++];
624 }
625 }
626 if(value!=values[i]) {
627 log_err("error: wrong value from UCPTRIE_FAST_U8_NEXT(%s)(from %d %lx->U+%04lx) (read %d bytes): "
628 "0x%lx instead of 0x%lx (from bytes %lx)\n",
629 testName, (int)prev8, (unsigned long)actualBytes, (long)c, (int)((p-s)-prev8),
630 (long)value, (long)values[i], (unsigned long)expectedBytes);
631 }
632 if(i8!=(p-s)) {
633 log_err("error: wrong end index from UCPTRIE_FAST_U8_NEXT(%s)(from %d %lx->U+%04lx): "
634 "%ld != %ld (bytes %lx)\n",
635 testName, (int)prev8, (unsigned long)actualBytes, (long)c,
636 (long)(p-s), (long)i8, (unsigned long)expectedBytes);
637 break;
638 }
639 ++i;
640 }
641
642 /* try backward */
643 p=limit;
644 i=countValues;
645 while(s<p) {
646 --i;
647 prev8=i8=(int32_t)(p-s);
648 U8_PREV(s, 0, i8, c);
649 if(valueWidth==UCPTRIE_VALUE_BITS_16) {
650 UCPTRIE_FAST_U8_PREV(trie, UCPTRIE_16, s, p, value);
651 } else if(valueWidth==UCPTRIE_VALUE_BITS_32) {
652 UCPTRIE_FAST_U8_PREV(trie, UCPTRIE_32, s, p, value);
653 } else {
654 UCPTRIE_FAST_U8_PREV(trie, UCPTRIE_8, s, p, value);
655 }
656 expectedBytes=0;
657 if(value!=values[i] || i8!=(p-s)) {
658 int32_t k=i8;
659 while(k<prev8) {
660 expectedBytes=(expectedBytes<<8)|s[k++];
661 }
662 }
663 if(i8==(p-s)) {
664 actualBytes=expectedBytes;
665 } else {
666 actualBytes=0;
667 int32_t k=(int32_t)(p-s);
668 while(k<prev8) {
669 actualBytes=(actualBytes<<8)|s[k++];
670 }
671 }
672 if(value!=values[i]) {
673 log_err("error: wrong value from UCPTRIE_FAST_U8_PREV(%s)(from %d %lx->U+%04lx) (read %d bytes): "
674 "0x%lx instead of 0x%lx (from bytes %lx)\n",
675 testName, (int)prev8, (unsigned long)actualBytes, (long)c, (int)(prev8-(p-s)),
676 (long)value, (long)values[i], (unsigned long)expectedBytes);
677 }
678 if(i8!=(p-s)) {
679 log_err("error: wrong end index from UCPTRIE_FAST_U8_PREV(%s)(from %d %lx->U+%04lx): "
680 "%ld != %ld (bytes %lx)\n",
681 testName, (int)prev8, (unsigned long)actualBytes, (long)c,
682 (long)(p-s), (long)i8, (unsigned long)expectedBytes);
683 break;
684 }
685 }
686 }
687
688 static void
testTrie(const char * testName,const UCPTrie * trie,UCPTrieType type,UCPTrieValueWidth valueWidth,const CheckRange checkRanges[],int32_t countCheckRanges)689 testTrie(const char *testName, const UCPTrie *trie,
690 UCPTrieType type, UCPTrieValueWidth valueWidth,
691 const CheckRange checkRanges[], int32_t countCheckRanges) {
692 testTrieGetters(testName, trie, type, valueWidth, checkRanges, countCheckRanges);
693 testTrieGetRanges(testName, trie, NULL, UCPMAP_RANGE_NORMAL, 0, checkRanges, countCheckRanges);
694 if (type == UCPTRIE_TYPE_FAST) {
695 testTrieUTF16(testName, trie, valueWidth, checkRanges, countCheckRanges);
696 testTrieUTF8(testName, trie, valueWidth, checkRanges, countCheckRanges);
697 }
698 }
699
700 static void
testBuilder(const char * testName,const UMutableCPTrie * mutableTrie,const CheckRange checkRanges[],int32_t countCheckRanges)701 testBuilder(const char *testName, const UMutableCPTrie *mutableTrie,
702 const CheckRange checkRanges[], int32_t countCheckRanges) {
703 testBuilderGetters(testName, mutableTrie, checkRanges, countCheckRanges);
704 testTrieGetRanges(testName, NULL, mutableTrie, UCPMAP_RANGE_NORMAL, 0, checkRanges, countCheckRanges);
705 }
706
707 static uint32_t storage[120000];
708 static uint32_t swapped[120000];
709
710 static void
testTrieSerialize(const char * testName,UMutableCPTrie * mutableTrie,UCPTrieType type,UCPTrieValueWidth valueWidth,UBool withSwap,const CheckRange checkRanges[],int32_t countCheckRanges)711 testTrieSerialize(const char *testName, UMutableCPTrie *mutableTrie,
712 UCPTrieType type, UCPTrieValueWidth valueWidth, UBool withSwap,
713 const CheckRange checkRanges[], int32_t countCheckRanges) {
714 UCPTrie *trie;
715 int32_t length1, length2, length3;
716 UErrorCode errorCode;
717
718 /* clone the trie so that the caller can reuse the original */
719 errorCode=U_ZERO_ERROR;
720 mutableTrie = umutablecptrie_clone(mutableTrie, &errorCode);
721 if(U_FAILURE(errorCode)) {
722 log_err("error: umutablecptrie_clone(%s) failed - %s\n",
723 testName, u_errorName(errorCode));
724 return;
725 }
726
727 /*
728 * This is not a loop, but simply a block that we can exit with "break"
729 * when something goes wrong.
730 */
731 do {
732 errorCode=U_ZERO_ERROR;
733 trie = umutablecptrie_buildImmutable(mutableTrie, type, valueWidth, &errorCode);
734 if (U_FAILURE(errorCode)) {
735 log_err("error: umutablecptrie_buildImmutable(%s) failed: %s\n",
736 testName, u_errorName(errorCode));
737 break;
738 }
739 errorCode=U_ZERO_ERROR;
740 length1=ucptrie_toBinary(trie, NULL, 0, &errorCode);
741 if(errorCode!=U_BUFFER_OVERFLOW_ERROR) {
742 log_err("error: ucptrie_toBinary(%s) preflighting set %s != U_BUFFER_OVERFLOW_ERROR\n",
743 testName, u_errorName(errorCode));
744 break;
745 }
746 errorCode=U_ZERO_ERROR;
747 length2=ucptrie_toBinary(trie, storage, sizeof(storage), &errorCode);
748 if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
749 log_err("error: ucptrie_toBinary(%s) needs more memory\n", testName);
750 break;
751 }
752 if(U_FAILURE(errorCode)) {
753 log_err("error: ucptrie_toBinary(%s) failed: %s\n", testName, u_errorName(errorCode));
754 break;
755 }
756 if(length1!=length2) {
757 log_err("error: trie serialization (%s) lengths different: "
758 "preflight vs. serialize\n", testName);
759 break;
760 }
761
762 testTrie(testName, trie, type, valueWidth, checkRanges, countCheckRanges);
763 ucptrie_close(trie);
764 trie=NULL;
765
766 if(withSwap) {
767 int32_t swappedLength;
768
769 UDataSwapper *ds;
770
771 /* swap to opposite-endian */
772 uprv_memset(swapped, 0x55, length2);
773 ds=udata_openSwapper(U_IS_BIG_ENDIAN, U_CHARSET_FAMILY,
774 !U_IS_BIG_ENDIAN, U_CHARSET_FAMILY, &errorCode);
775 swappedLength=ucptrie_swap(ds, storage, -1, NULL, &errorCode);
776 if(U_FAILURE(errorCode) || swappedLength!=length2) {
777 log_err("error: ucptrie_swap(%s to OE preflighting) failed (%s) "
778 "or before/after lengths different\n",
779 testName, u_errorName(errorCode));
780 udata_closeSwapper(ds);
781 break;
782 }
783 swappedLength=ucptrie_swap(ds, storage, length2, swapped, &errorCode);
784 udata_closeSwapper(ds);
785 if(U_FAILURE(errorCode) || swappedLength!=length2) {
786 log_err("error: ucptrie_swap(%s to OE) failed (%s) or before/after lengths different\n",
787 testName, u_errorName(errorCode));
788 break;
789 }
790
791 /* swap back to platform-endian */
792 uprv_memset(storage, 0xaa, length2);
793 ds=udata_openSwapper(!U_IS_BIG_ENDIAN, U_CHARSET_FAMILY,
794 U_IS_BIG_ENDIAN, U_CHARSET_FAMILY, &errorCode);
795 swappedLength=ucptrie_swap(ds, swapped, -1, NULL, &errorCode);
796 if(U_FAILURE(errorCode) || swappedLength!=length2) {
797 log_err("error: ucptrie_swap(%s to PE preflighting) failed (%s) "
798 "or before/after lengths different\n",
799 testName, u_errorName(errorCode));
800 udata_closeSwapper(ds);
801 break;
802 }
803 swappedLength=ucptrie_swap(ds, swapped, length2, storage, &errorCode);
804 udata_closeSwapper(ds);
805 if(U_FAILURE(errorCode) || swappedLength!=length2) {
806 log_err("error: ucptrie_swap(%s to PE) failed (%s) or before/after lengths different\n",
807 testName, u_errorName(errorCode));
808 break;
809 }
810 }
811
812 trie = ucptrie_openFromBinary(type, valueWidth, storage, length2, &length3, &errorCode);
813 if(U_FAILURE(errorCode)) {
814 log_err("error: ucptrie_openFromBinary(%s) failed, %s\n", testName, u_errorName(errorCode));
815 break;
816 }
817 if(type != ucptrie_getType(trie)) {
818 log_err("error: trie serialization (%s) did not preserve trie type\n", testName);
819 break;
820 }
821 if(valueWidth != ucptrie_getValueWidth(trie)) {
822 log_err("error: trie serialization (%s) did not preserve data value width\n", testName);
823 break;
824 }
825 if(length2!=length3) {
826 log_err("error: trie serialization (%s) lengths different: "
827 "serialize vs. unserialize\n", testName);
828 break;
829 }
830 /* overwrite the storage that is not supposed to be needed */
831 uprv_memset((char *)storage+length3, 0xfa, (int32_t)(sizeof(storage)-length3));
832
833 {
834 errorCode=U_ZERO_ERROR;
835 UCPTrie *any = ucptrie_openFromBinary(UCPTRIE_TYPE_ANY, UCPTRIE_VALUE_BITS_ANY,
836 storage, length3, NULL, &errorCode);
837 if (U_SUCCESS(errorCode)) {
838 if (type != ucptrie_getType(any)) {
839 log_err("error: ucptrie_openFromBinary("
840 "UCPTRIE_TYPE_ANY, UCPTRIE_VALUE_BITS_ANY).getType() wrong\n");
841 }
842 if (valueWidth != ucptrie_getValueWidth(any)) {
843 log_err("error: ucptrie_openFromBinary("
844 "UCPTRIE_TYPE_ANY, UCPTRIE_VALUE_BITS_ANY).getValueWidth() wrong\n");
845 }
846 ucptrie_close(any);
847 } else {
848 log_err("error: ucptrie_openFromBinary("
849 "UCPTRIE_TYPE_ANY, UCPTRIE_VALUE_BITS_ANY) failed - %s\n",
850 u_errorName(errorCode));
851 }
852 }
853
854 errorCode=U_ZERO_ERROR;
855 testTrie(testName, trie, type, valueWidth, checkRanges, countCheckRanges);
856 {
857 /* make a mutable trie from an immutable one */
858 uint32_t value, value2;
859 UMutableCPTrie *mutable2 = umutablecptrie_fromUCPTrie(trie, &errorCode);
860 if(U_FAILURE(errorCode)) {
861 log_err("error: umutablecptrie_fromUCPTrie(unserialized %s) failed - %s\n",
862 testName, u_errorName(errorCode));
863 break;
864 }
865
866 value=umutablecptrie_get(mutable2, 0xa1);
867 umutablecptrie_set(mutable2, 0xa1, 789, &errorCode);
868 value2=umutablecptrie_get(mutable2, 0xa1);
869 umutablecptrie_set(mutable2, 0xa1, value, &errorCode);
870 if(U_FAILURE(errorCode) || value2!=789) {
871 log_err("error: modifying a mutableTrie-from-UCPTrie (%s) failed - %s\n",
872 testName, u_errorName(errorCode));
873 }
874 testBuilder(testName, mutable2, checkRanges, countCheckRanges);
875 umutablecptrie_close(mutable2);
876 }
877 } while(0);
878
879 umutablecptrie_close(mutableTrie);
880 ucptrie_close(trie);
881 }
882
883 static UMutableCPTrie *
testTrieSerializeAllValueWidth(const char * testName,UMutableCPTrie * mutableTrie,UBool withClone,const CheckRange checkRanges[],int32_t countCheckRanges)884 testTrieSerializeAllValueWidth(const char *testName,
885 UMutableCPTrie *mutableTrie, UBool withClone,
886 const CheckRange checkRanges[], int32_t countCheckRanges) {
887 char name[40];
888 uint32_t oredValues = 0;
889 int32_t i;
890 for (i = 0; i < countCheckRanges; ++i) {
891 oredValues |= checkRanges[i].value;
892 }
893
894 testBuilder(testName, mutableTrie, checkRanges, countCheckRanges);
895
896 if (oredValues <= 0xffff) {
897 uprv_strcpy(name, testName);
898 uprv_strcat(name, ".16");
899 testTrieSerialize(name, mutableTrie,
900 UCPTRIE_TYPE_FAST, UCPTRIE_VALUE_BITS_16, withClone,
901 checkRanges, countCheckRanges);
902 }
903
904 uprv_strcpy(name, testName);
905 uprv_strcat(name, ".32");
906 testTrieSerialize(name, mutableTrie,
907 UCPTRIE_TYPE_FAST, UCPTRIE_VALUE_BITS_32, withClone,
908 checkRanges, countCheckRanges);
909
910 if (oredValues <= 0xff) {
911 uprv_strcpy(name, testName);
912 uprv_strcat(name, ".8");
913 testTrieSerialize(name, mutableTrie,
914 UCPTRIE_TYPE_FAST, UCPTRIE_VALUE_BITS_8, withClone,
915 checkRanges, countCheckRanges);
916 }
917
918 if (oredValues <= 0xffff) {
919 uprv_strcpy(name, testName);
920 uprv_strcat(name, ".small16");
921 testTrieSerialize(name, mutableTrie,
922 UCPTRIE_TYPE_SMALL, UCPTRIE_VALUE_BITS_16, withClone,
923 checkRanges, countCheckRanges);
924 }
925
926 return mutableTrie;
927 }
928
929 static UMutableCPTrie *
makeTrieWithRanges(const char * testName,UBool withClone,const SetRange setRanges[],int32_t countSetRanges,const CheckRange checkRanges[],int32_t countCheckRanges)930 makeTrieWithRanges(const char *testName, UBool withClone,
931 const SetRange setRanges[], int32_t countSetRanges,
932 const CheckRange checkRanges[], int32_t countCheckRanges) {
933 UMutableCPTrie *mutableTrie;
934 uint32_t initialValue, errorValue;
935 uint32_t value;
936 UChar32 start, limit;
937 int32_t i;
938 UErrorCode errorCode;
939
940 log_verbose("\ntesting Trie '%s'\n", testName);
941 errorCode=U_ZERO_ERROR;
942 getSpecialValues(checkRanges, countCheckRanges, &initialValue, &errorValue);
943 mutableTrie = umutablecptrie_open(initialValue, errorValue, &errorCode);
944 if(U_FAILURE(errorCode)) {
945 log_err("error: umutablecptrie_open(%s) failed: %s\n", testName, u_errorName(errorCode));
946 return NULL;
947 }
948
949 /* set values from setRanges[] */
950 for(i=0; i<countSetRanges; ++i) {
951 if(withClone && i==countSetRanges/2) {
952 /* switch to a clone in the middle of setting values */
953 UMutableCPTrie *clone = umutablecptrie_clone(mutableTrie, &errorCode);
954 if(U_FAILURE(errorCode)) {
955 log_err("error: umutablecptrie_clone(%s) failed - %s\n",
956 testName, u_errorName(errorCode));
957 errorCode=U_ZERO_ERROR; /* continue with the original */
958 } else {
959 umutablecptrie_close(mutableTrie);
960 mutableTrie = clone;
961 }
962 }
963 start=setRanges[i].start;
964 limit=setRanges[i].limit;
965 value=setRanges[i].value;
966 if ((limit - start) == 1) {
967 umutablecptrie_set(mutableTrie, start, value, &errorCode);
968 } else {
969 umutablecptrie_setRange(mutableTrie, start, limit-1, value, &errorCode);
970 }
971 }
972
973 if(U_SUCCESS(errorCode)) {
974 return mutableTrie;
975 } else {
976 log_err("error: setting values into a mutable trie (%s) failed - %s\n",
977 testName, u_errorName(errorCode));
978 umutablecptrie_close(mutableTrie);
979 return NULL;
980 }
981 }
982
983 static void
testTrieRanges(const char * testName,UBool withClone,const SetRange setRanges[],int32_t countSetRanges,const CheckRange checkRanges[],int32_t countCheckRanges)984 testTrieRanges(const char *testName, UBool withClone,
985 const SetRange setRanges[], int32_t countSetRanges,
986 const CheckRange checkRanges[], int32_t countCheckRanges) {
987 UMutableCPTrie *mutableTrie = makeTrieWithRanges(
988 testName, withClone, setRanges, countSetRanges, checkRanges, countCheckRanges);
989 if (mutableTrie != NULL) {
990 mutableTrie = testTrieSerializeAllValueWidth(testName, mutableTrie, withClone,
991 checkRanges, countCheckRanges);
992 umutablecptrie_close(mutableTrie);
993 }
994 }
995
996 /* test data ----------------------------------------------------------------*/
997
998 /* set consecutive ranges, even with value 0 */
999 static const SetRange
1000 setRanges1[]={
1001 { 0, 0x40, 0 },
1002 { 0x40, 0xe7, 0x34 },
1003 { 0xe7, 0x3400, 0 },
1004 { 0x3400, 0x9fa6, 0x61 },
1005 { 0x9fa6, 0xda9e, 0x31 },
1006 { 0xdada, 0xeeee, 0xff },
1007 { 0xeeee, 0x11111, 1 },
1008 { 0x11111, 0x44444, 0x61 },
1009 { 0x44444, 0x60003, 0 },
1010 { 0xf0003, 0xf0004, 0xf },
1011 { 0xf0004, 0xf0006, 0x10 },
1012 { 0xf0006, 0xf0007, 0x11 },
1013 { 0xf0007, 0xf0040, 0x12 },
1014 { 0xf0040, 0x110000, 0 }
1015 };
1016
1017 static const CheckRange
1018 checkRanges1[]={
1019 { 0, 0 },
1020 { 0x40, 0 },
1021 { 0xe7, 0x34 },
1022 { 0x3400, 0 },
1023 { 0x9fa6, 0x61 },
1024 { 0xda9e, 0x31 },
1025 { 0xdada, 0 },
1026 { 0xeeee, 0xff },
1027 { 0x11111, 1 },
1028 { 0x44444, 0x61 },
1029 { 0xf0003, 0 },
1030 { 0xf0004, 0xf },
1031 { 0xf0006, 0x10 },
1032 { 0xf0007, 0x11 },
1033 { 0xf0040, 0x12 },
1034 { 0x110000, 0 }
1035 };
1036
1037 /* set some interesting overlapping ranges */
1038 static const SetRange
1039 setRanges2[]={
1040 { 0x21, 0x7f, 0x5555 },
1041 { 0x2f800, 0x2fedc, 0x7a },
1042 { 0x72, 0xdd, 3 },
1043 { 0xdd, 0xde, 4 },
1044 { 0x201, 0x240, 6 }, /* 3 consecutive blocks with the same pattern but */
1045 { 0x241, 0x280, 6 }, /* discontiguous value ranges, testing iteration */
1046 { 0x281, 0x2c0, 6 },
1047 { 0x2f987, 0x2fa98, 5 },
1048 { 0x2f777, 0x2f883, 0 },
1049 { 0x2fedc, 0x2ffaa, 1 },
1050 { 0x2ffaa, 0x2ffab, 2 },
1051 { 0x2ffbb, 0x2ffc0, 7 }
1052 };
1053
1054 static const CheckRange
1055 checkRanges2[]={
1056 { 0, 0 },
1057 { 0x21, 0 },
1058 { 0x72, 0x5555 },
1059 { 0xdd, 3 },
1060 { 0xde, 4 },
1061 { 0x201, 0 },
1062 { 0x240, 6 },
1063 { 0x241, 0 },
1064 { 0x280, 6 },
1065 { 0x281, 0 },
1066 { 0x2c0, 6 },
1067 { 0x2f883, 0 },
1068 { 0x2f987, 0x7a },
1069 { 0x2fa98, 5 },
1070 { 0x2fedc, 0x7a },
1071 { 0x2ffaa, 1 },
1072 { 0x2ffab, 2 },
1073 { 0x2ffbb, 0 },
1074 { 0x2ffc0, 7 },
1075 { 0x110000, 0 }
1076 };
1077
1078 /* use a non-zero initial value */
1079 static const SetRange
1080 setRanges3[]={
1081 { 0x31, 0xa4, 1 },
1082 { 0x3400, 0x6789, 2 },
1083 { 0x8000, 0x89ab, 9 },
1084 { 0x9000, 0xa000, 4 },
1085 { 0xabcd, 0xbcde, 3 },
1086 { 0x55555, 0x110000, 6 }, /* highStart<U+ffff with non-initialValue */
1087 { 0xcccc, 0x55555, 6 }
1088 };
1089
1090 static const CheckRange
1091 checkRanges3[]={
1092 { 0, 9 }, /* non-zero initialValue */
1093 { 0x31, 9 },
1094 { 0xa4, 1 },
1095 { 0x3400, 9 },
1096 { 0x6789, 2 },
1097 { 0x9000, 9 },
1098 { 0xa000, 4 },
1099 { 0xabcd, 9 },
1100 { 0xbcde, 3 },
1101 { 0xcccc, 9 },
1102 { 0x110000, 6 }
1103 };
1104
1105 /* empty or single-value tries, testing highStart==0 */
1106 static const SetRange
1107 setRangesEmpty[]={
1108 { 0, 0, 0 }, /* need some values for it to compile */
1109 };
1110
1111 static const CheckRange
1112 checkRangesEmpty[]={
1113 { 0, 3 },
1114 { 0x110000, 3 }
1115 };
1116
1117 static const SetRange
1118 setRangesSingleValue[]={
1119 { 0, 0x110000, 5 },
1120 };
1121
1122 static const CheckRange
1123 checkRangesSingleValue[]={
1124 { 0, 3 },
1125 { 0x110000, 5 }
1126 };
1127
1128 static void
TrieTestSet1(void)1129 TrieTestSet1(void) {
1130 testTrieRanges("set1", FALSE,
1131 setRanges1, UPRV_LENGTHOF(setRanges1),
1132 checkRanges1, UPRV_LENGTHOF(checkRanges1));
1133 }
1134
1135 static void
TrieTestSet2Overlap(void)1136 TrieTestSet2Overlap(void) {
1137 testTrieRanges("set2-overlap", FALSE,
1138 setRanges2, UPRV_LENGTHOF(setRanges2),
1139 checkRanges2, UPRV_LENGTHOF(checkRanges2));
1140 }
1141
1142 static void
TrieTestSet3Initial9(void)1143 TrieTestSet3Initial9(void) {
1144 testTrieRanges("set3-initial-9", FALSE,
1145 setRanges3, UPRV_LENGTHOF(setRanges3),
1146 checkRanges3, UPRV_LENGTHOF(checkRanges3));
1147 }
1148
1149 static void
TrieTestSetEmpty(void)1150 TrieTestSetEmpty(void) {
1151 testTrieRanges("set-empty", FALSE,
1152 setRangesEmpty, 0,
1153 checkRangesEmpty, UPRV_LENGTHOF(checkRangesEmpty));
1154 }
1155
1156 static void
TrieTestSetSingleValue(void)1157 TrieTestSetSingleValue(void) {
1158 testTrieRanges("set-single-value", FALSE,
1159 setRangesSingleValue, UPRV_LENGTHOF(setRangesSingleValue),
1160 checkRangesSingleValue, UPRV_LENGTHOF(checkRangesSingleValue));
1161 }
1162
1163 static void
TrieTestSet2OverlapWithClone(void)1164 TrieTestSet2OverlapWithClone(void) {
1165 testTrieRanges("set2-overlap.withClone", TRUE,
1166 setRanges2, UPRV_LENGTHOF(setRanges2),
1167 checkRanges2, UPRV_LENGTHOF(checkRanges2));
1168 }
1169
1170 /* test mutable-trie memory management -------------------------------------- */
1171
1172 static void
FreeBlocksTest(void)1173 FreeBlocksTest(void) {
1174 static const CheckRange
1175 checkRanges[]={
1176 { 0, 1 },
1177 { 0x740, 1 },
1178 { 0x780, 2 },
1179 { 0x880, 3 },
1180 { 0x110000, 1 }
1181 };
1182 static const char *const testName="free-blocks";
1183
1184 UMutableCPTrie *mutableTrie;
1185 int32_t i;
1186 UErrorCode errorCode;
1187
1188 errorCode=U_ZERO_ERROR;
1189 mutableTrie=umutablecptrie_open(1, 0xad, &errorCode);
1190 if(U_FAILURE(errorCode)) {
1191 log_err("error: umutablecptrie_open(%s) failed: %s\n", testName, u_errorName(errorCode));
1192 return;
1193 }
1194
1195 /*
1196 * Repeatedly set overlapping same-value ranges to stress the free-data-block management.
1197 * If it fails, it will overflow the data array.
1198 */
1199 for(i=0; i<(0x120000>>4)/2; ++i) { // 4=UCPTRIE_SHIFT_3
1200 umutablecptrie_setRange(mutableTrie, 0x740, 0x840-1, 1, &errorCode);
1201 umutablecptrie_setRange(mutableTrie, 0x780, 0x880-1, 1, &errorCode);
1202 umutablecptrie_setRange(mutableTrie, 0x740, 0x840-1, 2, &errorCode);
1203 umutablecptrie_setRange(mutableTrie, 0x780, 0x880-1, 3, &errorCode);
1204 }
1205 /* make blocks that will be free during compaction */
1206 umutablecptrie_setRange(mutableTrie, 0x1000, 0x3000-1, 2, &errorCode);
1207 umutablecptrie_setRange(mutableTrie, 0x2000, 0x4000-1, 3, &errorCode);
1208 umutablecptrie_setRange(mutableTrie, 0x1000, 0x4000-1, 1, &errorCode);
1209 if(U_FAILURE(errorCode)) {
1210 log_err("error: setting lots of ranges into a mutable trie (%s) failed - %s\n",
1211 testName, u_errorName(errorCode));
1212 umutablecptrie_close(mutableTrie);
1213 return;
1214 }
1215
1216 mutableTrie = testTrieSerializeAllValueWidth(testName, mutableTrie, FALSE,
1217 checkRanges, UPRV_LENGTHOF(checkRanges));
1218 umutablecptrie_close(mutableTrie);
1219 }
1220
1221 static void
GrowDataArrayTest(void)1222 GrowDataArrayTest(void) {
1223 static const CheckRange
1224 checkRanges[]={
1225 { 0, 1 },
1226 { 0x720, 2 },
1227 { 0x7a0, 3 },
1228 { 0x8a0, 4 },
1229 { 0x110000, 5 }
1230 };
1231 static const char *const testName="grow-data";
1232
1233 UMutableCPTrie *mutableTrie;
1234 int32_t i;
1235 UErrorCode errorCode;
1236
1237 errorCode=U_ZERO_ERROR;
1238 mutableTrie=umutablecptrie_open(1, 0xad, &errorCode);
1239 if(U_FAILURE(errorCode)) {
1240 log_err("error: umutablecptrie_open(%s) failed: %s\n", testName, u_errorName(errorCode));
1241 return;
1242 }
1243
1244 /*
1245 * Use umutablecptrie_set() not umutablecptrie_setRange() to write non-initialValue-data.
1246 * Should grow/reallocate the data array to a sufficient length.
1247 */
1248 for(i=0; i<0x1000; ++i) {
1249 umutablecptrie_set(mutableTrie, i, 2, &errorCode);
1250 }
1251 for(i=0x720; i<0x1100; ++i) { /* some overlap */
1252 umutablecptrie_set(mutableTrie, i, 3, &errorCode);
1253 }
1254 for(i=0x7a0; i<0x900; ++i) {
1255 umutablecptrie_set(mutableTrie, i, 4, &errorCode);
1256 }
1257 for(i=0x8a0; i<0x110000; ++i) {
1258 umutablecptrie_set(mutableTrie, i, 5, &errorCode);
1259 }
1260 if(U_FAILURE(errorCode)) {
1261 log_err("error: setting lots of values into a mutable trie (%s) failed - %s\n",
1262 testName, u_errorName(errorCode));
1263 umutablecptrie_close(mutableTrie);
1264 return;
1265 }
1266
1267 mutableTrie = testTrieSerializeAllValueWidth(testName, mutableTrie, FALSE,
1268 checkRanges, UPRV_LENGTHOF(checkRanges));
1269 umutablecptrie_close(mutableTrie);
1270 }
1271
1272 static void
ManyAllSameBlocksTest(void)1273 ManyAllSameBlocksTest(void) {
1274 static const char *const testName="many-all-same";
1275
1276 UMutableCPTrie *mutableTrie;
1277 int32_t i;
1278 UErrorCode errorCode;
1279 CheckRange checkRanges[(0x110000 >> 12) + 1];
1280
1281 errorCode = U_ZERO_ERROR;
1282 mutableTrie = umutablecptrie_open(0xff33, 0xad, &errorCode);
1283 if (U_FAILURE(errorCode)) {
1284 log_err("error: umutablecptrie_open(%s) failed: %s\n", testName, u_errorName(errorCode));
1285 return;
1286 }
1287 checkRanges[0].limit = 0;
1288 checkRanges[0].value = 0xff33; // initialValue
1289
1290 // Many all-same-value blocks.
1291 for (i = 0; i < 0x110000; i += 0x1000) {
1292 uint32_t value = i >> 12;
1293 umutablecptrie_setRange(mutableTrie, i, i + 0xfff, value, &errorCode);
1294 checkRanges[value + 1].limit = i + 0x1000;
1295 checkRanges[value + 1].value = value;
1296 }
1297 for (i = 0; i < 0x110000; i += 0x1000) {
1298 uint32_t expected = i >> 12;
1299 uint32_t v0 = umutablecptrie_get(mutableTrie, i);
1300 uint32_t vfff = umutablecptrie_get(mutableTrie, i + 0xfff);
1301 if (v0 != expected || vfff != expected) {
1302 log_err("error: UMutableCPTrie U+%04lx unexpected value\n", (long)i);
1303 }
1304 }
1305
1306 mutableTrie = testTrieSerializeAllValueWidth(testName, mutableTrie, FALSE,
1307 checkRanges, UPRV_LENGTHOF(checkRanges));
1308 umutablecptrie_close(mutableTrie);
1309 }
1310
1311 static void
MuchDataTest(void)1312 MuchDataTest(void) {
1313 static const char *const testName="much-data";
1314
1315 UMutableCPTrie *mutableTrie;
1316 int32_t r, c;
1317 UErrorCode errorCode = U_ZERO_ERROR;
1318 CheckRange checkRanges[(0x10000 >> 6) + (0x10240 >> 4) + 10];
1319
1320 mutableTrie = umutablecptrie_open(0xff33, 0xad, &errorCode);
1321 if (U_FAILURE(errorCode)) {
1322 log_err("error: umutablecptrie_open(%s) failed: %s\n", testName, u_errorName(errorCode));
1323 return;
1324 }
1325 checkRanges[0].limit = 0;
1326 checkRanges[0].value = 0xff33; // initialValue
1327 r = 1;
1328
1329 // Add much data that does not compact well,
1330 // to get more than 128k data values after compaction.
1331 for (c = 0; c < 0x10000; c += 0x40) {
1332 uint32_t value = c >> 4;
1333 umutablecptrie_setRange(mutableTrie, c, c + 0x3f, value, &errorCode);
1334 checkRanges[r].limit = c + 0x40;
1335 checkRanges[r++].value = value;
1336 }
1337 checkRanges[r].limit = 0x20000;
1338 checkRanges[r++].value = 0xff33;
1339 for (c = 0x20000; c < 0x30230; c += 0x10) {
1340 uint32_t value = c >> 4;
1341 umutablecptrie_setRange(mutableTrie, c, c + 0xf, value, &errorCode);
1342 checkRanges[r].limit = c + 0x10;
1343 checkRanges[r++].value = value;
1344 }
1345 umutablecptrie_setRange(mutableTrie, 0x30230, 0x30233, 0x3023, &errorCode);
1346 checkRanges[r].limit = 0x30234;
1347 checkRanges[r++].value = 0x3023;
1348 umutablecptrie_setRange(mutableTrie, 0x30234, 0xdffff, 0x5005, &errorCode);
1349 checkRanges[r].limit = 0xe0000;
1350 checkRanges[r++].value = 0x5005;
1351 umutablecptrie_setRange(mutableTrie, 0xe0000, 0x10ffff, 0x9009, &errorCode);
1352 checkRanges[r].limit = 0x110000;
1353 checkRanges[r++].value = 0x9009;
1354 if (U_FAILURE(errorCode)) {
1355 log_err("error: setting lots of values into a mutable trie (%s) failed - %s\n",
1356 testName, u_errorName(errorCode));
1357 umutablecptrie_close(mutableTrie);
1358 return;
1359 }
1360 U_ASSERT(r <= UPRV_LENGTHOF(checkRanges));
1361
1362 testBuilder(testName, mutableTrie, checkRanges, r);
1363 testTrieSerialize("much-data.16", mutableTrie,
1364 UCPTRIE_TYPE_FAST, UCPTRIE_VALUE_BITS_16, FALSE, checkRanges, r);
1365 umutablecptrie_close(mutableTrie);
1366 }
1367
testGetRangesFixedSurr(const char * testName,const UMutableCPTrie * mutableTrie,UCPMapRangeOption option,const CheckRange checkRanges[],int32_t countCheckRanges)1368 static void testGetRangesFixedSurr(const char *testName, const UMutableCPTrie *mutableTrie,
1369 UCPMapRangeOption option,
1370 const CheckRange checkRanges[], int32_t countCheckRanges) {
1371 testTrieGetRanges(testName, NULL, mutableTrie, option, 5, checkRanges, countCheckRanges);
1372 UErrorCode errorCode = U_ZERO_ERROR;
1373 UMutableCPTrie *clone = umutablecptrie_clone(mutableTrie, &errorCode);
1374 UCPTrie *trie;
1375 if (U_FAILURE(errorCode)) {
1376 log_err("error: umutablecptrie_clone(%s) failed: %s\n", testName, u_errorName(errorCode));
1377 return;
1378 }
1379 trie = umutablecptrie_buildImmutable(clone, UCPTRIE_TYPE_FAST, UCPTRIE_VALUE_BITS_16, &errorCode);
1380 umutablecptrie_close(clone);
1381 if (U_FAILURE(errorCode)) {
1382 log_err("error: umutablecptrie_buildImmutable(%s) failed: %s\n", testName, u_errorName(errorCode));
1383 return;
1384 }
1385 testTrieGetRanges(testName, trie, NULL, option, 5, checkRanges, countCheckRanges);
1386 ucptrie_close(trie);
1387 }
1388
1389 static void
TrieTestGetRangesFixedSurr(void)1390 TrieTestGetRangesFixedSurr(void) {
1391 static const SetRange
1392 setRangesFixedSurr[]={
1393 { 0xd000, 0xd7ff, 5 },
1394 { 0xd7ff, 0xe001, 3 },
1395 { 0xe001, 0xf900, 5 },
1396 };
1397
1398 static const CheckRange
1399 checkRangesFixedLeadSurr1[]={
1400 { 0, 0 },
1401 { 0xd000, 0 },
1402 { 0xd7ff, 5 },
1403 { 0xd800, 3 },
1404 { 0xdc00, 5 },
1405 { 0xe001, 3 },
1406 { 0xf900, 5 },
1407 { 0x110000, 0 }
1408 };
1409
1410 static const CheckRange
1411 checkRangesFixedAllSurr1[]={
1412 { 0, 0 },
1413 { 0xd000, 0 },
1414 { 0xd7ff, 5 },
1415 { 0xd800, 3 },
1416 { 0xe000, 5 },
1417 { 0xe001, 3 },
1418 { 0xf900, 5 },
1419 { 0x110000, 0 }
1420 };
1421
1422 static const CheckRange
1423 checkRangesFixedLeadSurr3[]={
1424 { 0, 0 },
1425 { 0xd000, 0 },
1426 { 0xdc00, 5 },
1427 { 0xe001, 3 },
1428 { 0xf900, 5 },
1429 { 0x110000, 0 }
1430 };
1431
1432 static const CheckRange
1433 checkRangesFixedAllSurr3[]={
1434 { 0, 0 },
1435 { 0xd000, 0 },
1436 { 0xe000, 5 },
1437 { 0xe001, 3 },
1438 { 0xf900, 5 },
1439 { 0x110000, 0 }
1440 };
1441
1442 static const CheckRange
1443 checkRangesFixedSurr4[]={
1444 { 0, 0 },
1445 { 0xd000, 0 },
1446 { 0xf900, 5 },
1447 { 0x110000, 0 }
1448 };
1449
1450 UMutableCPTrie *mutableTrie = makeTrieWithRanges(
1451 "fixedSurr", FALSE, setRangesFixedSurr, UPRV_LENGTHOF(setRangesFixedSurr),
1452 checkRangesFixedLeadSurr1, UPRV_LENGTHOF(checkRangesFixedLeadSurr1));
1453 UErrorCode errorCode = U_ZERO_ERROR;
1454 if (mutableTrie == NULL) {
1455 return;
1456 }
1457 testGetRangesFixedSurr("fixedLeadSurr1", mutableTrie, UCPMAP_RANGE_FIXED_LEAD_SURROGATES,
1458 checkRangesFixedLeadSurr1, UPRV_LENGTHOF(checkRangesFixedLeadSurr1));
1459 testGetRangesFixedSurr("fixedAllSurr1", mutableTrie, UCPMAP_RANGE_FIXED_ALL_SURROGATES,
1460 checkRangesFixedAllSurr1, UPRV_LENGTHOF(checkRangesFixedAllSurr1));
1461 // Setting a range in the middle of lead surrogates makes no difference.
1462 umutablecptrie_setRange(mutableTrie, 0xd844, 0xd899, 5, &errorCode);
1463 if (U_FAILURE(errorCode)) {
1464 log_err("error: umutablecptrie_setRange(fixedSurr2) failed: %s\n", u_errorName(errorCode));
1465 umutablecptrie_close(mutableTrie);
1466 return;
1467 }
1468 testGetRangesFixedSurr("fixedLeadSurr2", mutableTrie, UCPMAP_RANGE_FIXED_LEAD_SURROGATES,
1469 checkRangesFixedLeadSurr1, UPRV_LENGTHOF(checkRangesFixedLeadSurr1));
1470 // Bridge the gap before the lead surrogates.
1471 umutablecptrie_set(mutableTrie, 0xd7ff, 5, &errorCode);
1472 if (U_FAILURE(errorCode)) {
1473 log_err("error: umutablecptrie_set(fixedSurr3) failed: %s\n", u_errorName(errorCode));
1474 umutablecptrie_close(mutableTrie);
1475 return;
1476 }
1477 testGetRangesFixedSurr("fixedLeadSurr3", mutableTrie, UCPMAP_RANGE_FIXED_LEAD_SURROGATES,
1478 checkRangesFixedLeadSurr3, UPRV_LENGTHOF(checkRangesFixedLeadSurr3));
1479 testGetRangesFixedSurr("fixedAllSurr3", mutableTrie, UCPMAP_RANGE_FIXED_ALL_SURROGATES,
1480 checkRangesFixedAllSurr3, UPRV_LENGTHOF(checkRangesFixedAllSurr3));
1481 // Bridge the gap after the trail surrogates.
1482 umutablecptrie_set(mutableTrie, 0xe000, 5, &errorCode);
1483 if (U_FAILURE(errorCode)) {
1484 log_err("error: umutablecptrie_set(fixedSurr4) failed: %s\n", u_errorName(errorCode));
1485 umutablecptrie_close(mutableTrie);
1486 return;
1487 }
1488 testGetRangesFixedSurr("fixedSurr4", mutableTrie, UCPMAP_RANGE_FIXED_ALL_SURROGATES,
1489 checkRangesFixedSurr4, UPRV_LENGTHOF(checkRangesFixedSurr4));
1490 umutablecptrie_close(mutableTrie);
1491 }
1492
TestSmallNullBlockMatchesFast(void)1493 static void TestSmallNullBlockMatchesFast(void) {
1494 // The initial builder+getRange code had a bug:
1495 // When there is no null data block in the fast-index range,
1496 // but a fast-range data block starts with enough values to match a small data block,
1497 // then getRange() got confused.
1498 // The builder must prevent this.
1499 static const SetRange setRanges[] = {
1500 { 0, 0x880, 1 },
1501 // U+0880..U+088F map to initial value 0, potential match for small null data block.
1502 { 0x890, 0x1040, 2 },
1503 // U+1040..U+1050 map to 0.
1504 // First small null data block in a small-type trie.
1505 // In a fast-type trie, it is ok to match a small null data block at U+1041
1506 // but not at U+1040.
1507 { 0x1051, 0x10000, 3 },
1508 // No fast data block (block length 64) filled with 0 regardless of trie type.
1509 // Need more blocks filled with 0 than the largest range above,
1510 // and need a highStart above that so that it actually counts.
1511 { 0x20000, 0x110000, 9 }
1512 };
1513
1514 static const CheckRange checkRanges[] = {
1515 { 0x0880, 1 },
1516 { 0x0890, 0 },
1517 { 0x1040, 2 },
1518 { 0x1051, 0 },
1519 { 0x10000, 3 },
1520 { 0x20000, 0 },
1521 { 0x110000, 9 }
1522 };
1523
1524 testTrieRanges("small0-in-fast", FALSE,
1525 setRanges, UPRV_LENGTHOF(setRanges),
1526 checkRanges, UPRV_LENGTHOF(checkRanges));
1527 }
1528
ShortAllSameBlocksTest(void)1529 static void ShortAllSameBlocksTest(void) {
1530 static const char *const testName = "short-all-same";
1531 // Many all-same-value blocks but only of the small block length used in the mutable trie.
1532 // The builder code needs to turn a group of short ALL_SAME blocks below fastLimit
1533 // into a MIXED block, and reserve data array capacity for that.
1534 UErrorCode errorCode = U_ZERO_ERROR;
1535 UMutableCPTrie *mutableTrie = umutablecptrie_open(0, 0xad, &errorCode);
1536 CheckRange checkRanges[0x101];
1537 int32_t i;
1538 if (U_FAILURE(errorCode)) {
1539 log_err("error: umutablecptrie_open(%s) failed: %s\n", testName, u_errorName(errorCode));
1540 return;
1541 }
1542 for (i = 0; i < 0x1000; i += 0x10) {
1543 uint32_t value = i >> 4;
1544 umutablecptrie_setRange(mutableTrie, i, i + 0xf, value, &errorCode);
1545 checkRanges[value].limit = i + 0x10;
1546 checkRanges[value].value = value;
1547 }
1548 checkRanges[0x100].limit = 0x110000;
1549 checkRanges[0x100].value = 0;
1550 if (U_FAILURE(errorCode)) {
1551 log_err("error: setting values into a mutable trie (%s) failed - %s\n",
1552 testName, u_errorName(errorCode));
1553 umutablecptrie_close(mutableTrie);
1554 return;
1555 }
1556
1557 mutableTrie = testTrieSerializeAllValueWidth(testName, mutableTrie, FALSE,
1558 checkRanges, UPRV_LENGTHOF(checkRanges));
1559 umutablecptrie_close(mutableTrie);
1560 }
1561
1562 void
addUCPTrieTest(TestNode ** root)1563 addUCPTrieTest(TestNode** root) {
1564 addTest(root, &TrieTestSet1, "tsutil/ucptrietest/TrieTestSet1");
1565 addTest(root, &TrieTestSet2Overlap, "tsutil/ucptrietest/TrieTestSet2Overlap");
1566 addTest(root, &TrieTestSet3Initial9, "tsutil/ucptrietest/TrieTestSet3Initial9");
1567 addTest(root, &TrieTestSetEmpty, "tsutil/ucptrietest/TrieTestSetEmpty");
1568 addTest(root, &TrieTestSetSingleValue, "tsutil/ucptrietest/TrieTestSetSingleValue");
1569 addTest(root, &TrieTestSet2OverlapWithClone, "tsutil/ucptrietest/TrieTestSet2OverlapWithClone");
1570 addTest(root, &FreeBlocksTest, "tsutil/ucptrietest/FreeBlocksTest");
1571 addTest(root, &GrowDataArrayTest, "tsutil/ucptrietest/GrowDataArrayTest");
1572 addTest(root, &ManyAllSameBlocksTest, "tsutil/ucptrietest/ManyAllSameBlocksTest");
1573 addTest(root, &MuchDataTest, "tsutil/ucptrietest/MuchDataTest");
1574 addTest(root, &TrieTestGetRangesFixedSurr, "tsutil/ucptrietest/TrieTestGetRangesFixedSurr");
1575 addTest(root, &TestSmallNullBlockMatchesFast, "tsutil/ucptrietest/TestSmallNullBlockMatchesFast");
1576 addTest(root, &ShortAllSameBlocksTest, "tsutil/ucptrietest/ShortAllSameBlocksTest");
1577 }
1578