icu/icu4c/source/test/cintltst/trie2test.c
Fredrik Roubert 030fa1a479 ICU-21148 Consistently use standard lowercase true/false everywhere.
This is the normal standard way in C, C++ as well as Java and there's no
longer any reason for ICU to be different. The various internal macros
providing custom boolean constants can all be deleted and code as well
as documentation can be updated to use lowercase true/false everywhere.
2022-09-07 20:56:33 +02:00

1437 lines
50 KiB
C

// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
******************************************************************************
*
* Copyright (C) 2001-2014, International Business Machines
* Corporation and others. All Rights Reserved.
*
******************************************************************************
* file name: trietest.c
* encoding: UTF-8
* tab size: 8 (not used)
* indentation:4
*
* created on: 2008sep01 (starting from a copy of trietest.c)
* created by: Markus W. Scherer
*/
#include <stdbool.h>
#include <stdio.h>
#include "unicode/utypes.h"
#include "unicode/utf8.h"
#include "utrie2.h"
#include "utrie.h"
#include "cstring.h"
#include "cmemory.h"
#include "udataswp.h"
#include "cintltst.h"
void addTrie2Test(TestNode** root);
/* Values for setting possibly overlapping, out-of-order ranges of values */
typedef struct SetRange {
UChar32 start, limit;
uint32_t value;
UBool overwrite;
} SetRange;
/*
* Values for testing:
* value is set from the previous boundary's limit to before
* this boundary's limit
*
* There must be an entry with limit 0 and the intialValue.
* It may be preceded by an entry with negative limit and the errorValue.
*/
typedef struct CheckRange {
UChar32 limit;
uint32_t value;
} CheckRange;
static int32_t
skipSpecialValues(const CheckRange checkRanges[], int32_t countCheckRanges) {
int32_t i;
for(i=0; i<countCheckRanges && checkRanges[i].limit<=0; ++i) {}
return i;
}
static int32_t
getSpecialValues(const CheckRange checkRanges[], int32_t countCheckRanges,
uint32_t *pInitialValue, uint32_t *pErrorValue) {
int32_t i=0;
if(i<countCheckRanges && checkRanges[i].limit<0) {
*pErrorValue=checkRanges[i++].value;
} else {
*pErrorValue=0xbad;
}
if(i<countCheckRanges && checkRanges[i].limit==0) {
*pInitialValue=checkRanges[i++].value;
} else {
*pInitialValue=0;
}
return i;
}
/* utrie2_enum() callback, modifies a value */
static uint32_t U_CALLCONV
testEnumValue(const void *context, uint32_t value) {
(void)context; // suppress compiler warnings about unused variable
return value^0x5555;
}
/* utrie2_enum() callback, verifies a range */
static UBool U_CALLCONV
testEnumRange(const void *context, UChar32 start, UChar32 end, uint32_t value) {
const CheckRange **pb=(const CheckRange **)context;
const CheckRange *b=(*pb)++;
UChar32 limit=end+1;
value^=0x5555;
if(start!=(b-1)->limit || limit!=b->limit || value!=b->value) {
log_err("error: utrie2_enum() delivers wrong range [U+%04lx..U+%04lx].0x%lx instead of [U+%04lx..U+%04lx].0x%lx\n",
(long)start, (long)end, (long)value,
(long)(b-1)->limit, (long)b->limit-1, (long)b->value);
}
return true;
}
static void
testTrieEnum(const char *testName,
const UTrie2 *trie,
const CheckRange checkRanges[], int32_t countCheckRanges) {
(void)testName; // suppress compiler warnings about unused variable
/* skip over special values */
while(countCheckRanges>0 && checkRanges[0].limit<=0) {
++checkRanges;
--countCheckRanges;
}
utrie2_enum(trie, testEnumValue, testEnumRange, &checkRanges);
}
/* verify all expected values via UTRIE2_GETxx() */
static void
testTrieGetters(const char *testName,
const UTrie2 *trie, UTrie2ValueBits valueBits,
const CheckRange checkRanges[], int32_t countCheckRanges) {
uint32_t initialValue, errorValue;
uint32_t value, value2;
UChar32 start, limit;
int32_t i, countSpecials;
UBool isFrozen=utrie2_isFrozen(trie);
const char *const typeName= isFrozen ? "frozen trie" : "newTrie";
countSpecials=getSpecialValues(checkRanges, countCheckRanges, &initialValue, &errorValue);
start=0;
for(i=countSpecials; i<countCheckRanges; ++i) {
limit=checkRanges[i].limit;
value=checkRanges[i].value;
while(start<limit) {
if(isFrozen) {
if(start<=0xffff) {
if(!U_IS_LEAD(start)) {
if(valueBits==UTRIE2_16_VALUE_BITS) {
value2=UTRIE2_GET16_FROM_U16_SINGLE_LEAD(trie, start);
} else {
value2=UTRIE2_GET32_FROM_U16_SINGLE_LEAD(trie, start);
}
if(value!=value2) {
log_err("error: %s(%s).fromBMP(U+%04lx)==0x%lx instead of 0x%lx\n",
typeName, testName, (long)start, (long)value2, (long)value);
}
}
} else {
if(valueBits==UTRIE2_16_VALUE_BITS) {
value2=UTRIE2_GET16_FROM_SUPP(trie, start);
} else {
value2=UTRIE2_GET32_FROM_SUPP(trie, start);
}
if(value!=value2) {
log_err("error: %s(%s).fromSupp(U+%04lx)==0x%lx instead of 0x%lx\n",
typeName, testName, (long)start, (long)value2, (long)value);
}
}
if(valueBits==UTRIE2_16_VALUE_BITS) {
value2=UTRIE2_GET16(trie, start);
} else {
value2=UTRIE2_GET32(trie, start);
}
if(value!=value2) {
log_err("error: %s(%s).get(U+%04lx)==0x%lx instead of 0x%lx\n",
typeName, testName, (long)start, (long)value2, (long)value);
}
}
value2=utrie2_get32(trie, start);
if(value!=value2) {
log_err("error: %s(%s).get32(U+%04lx)==0x%lx instead of 0x%lx\n",
typeName, testName, (long)start, (long)value2, (long)value);
}
++start;
}
}
if(isFrozen) {
/* test linear ASCII range from the data array pointer (access to "internal" field) */
start=0;
for(i=countSpecials; i<countCheckRanges && start<=0x7f; ++i) {
limit=checkRanges[i].limit;
value=checkRanges[i].value;
while(start<limit && start<=0x7f) {
if(valueBits==UTRIE2_16_VALUE_BITS) {
value2=trie->data16[start];
} else {
value2=trie->data32[start];
}
if(value!=value2) {
log_err("error: %s(%s).asciiData[U+%04lx]==0x%lx instead of 0x%lx\n",
typeName, testName, (long)start, (long)value2, (long)value);
}
++start;
}
}
while(start<=0xbf) {
if(valueBits==UTRIE2_16_VALUE_BITS) {
value2=trie->data16[start];
} else {
value2=trie->data32[start];
}
if(errorValue!=value2) {
log_err("error: %s(%s).badData[U+%04lx]==0x%lx instead of 0x%lx\n",
typeName, testName, (long)start, (long)value2, (long)errorValue);
}
++start;
}
}
if(0!=strncmp(testName, "dummy", 5) && 0!=strncmp(testName, "trie1", 5)) {
/* test values for lead surrogate code units */
for(start=0xd7ff; start<0xdc01; ++start) {
switch(start) {
case 0xd7ff:
case 0xdc00:
value=errorValue;
break;
case 0xd800:
value=90;
break;
case 0xd999:
value=94;
break;
case 0xdbff:
value=99;
break;
default:
value=initialValue;
break;
}
if(isFrozen && U_IS_LEAD(start)) {
if(valueBits==UTRIE2_16_VALUE_BITS) {
value2=UTRIE2_GET16_FROM_U16_SINGLE_LEAD(trie, start);
} else {
value2=UTRIE2_GET32_FROM_U16_SINGLE_LEAD(trie, start);
}
if(value2!=value) {
log_err("error: %s(%s).LSCU(U+%04lx)==0x%lx instead of 0x%lx\n",
typeName, testName, (long)start, (long)value2, (long)value);
}
}
value2=utrie2_get32FromLeadSurrogateCodeUnit(trie, start);
if(value2!=value) {
log_err("error: %s(%s).lscu(U+%04lx)==0x%lx instead of 0x%lx\n",
typeName, testName, (long)start, (long)value2, (long)value);
}
}
}
/* test errorValue */
if(isFrozen) {
if(valueBits==UTRIE2_16_VALUE_BITS) {
value=UTRIE2_GET16(trie, -1);
value2=UTRIE2_GET16(trie, 0x110000);
} else {
value=UTRIE2_GET32(trie, -1);
value2=UTRIE2_GET32(trie, 0x110000);
}
if(value!=errorValue || value2!=errorValue) {
log_err("error: %s(%s).get(out of range) != errorValue\n",
typeName, testName);
}
}
value=utrie2_get32(trie, -1);
value2=utrie2_get32(trie, 0x110000);
if(value!=errorValue || value2!=errorValue) {
log_err("error: %s(%s).get32(out of range) != errorValue\n",
typeName, testName);
}
}
static void
testTrieUTF16(const char *testName,
const UTrie2 *trie, UTrie2ValueBits valueBits,
const CheckRange checkRanges[], int32_t countCheckRanges) {
UChar s[200];
uint32_t values[100];
const UChar *p, *limit;
uint32_t value;
UChar32 prevCP, c, c2;
int32_t i, length, sIndex, countValues;
/* write a string */
prevCP=0;
length=countValues=0;
for(i=skipSpecialValues(checkRanges, countCheckRanges); i<countCheckRanges; ++i) {
value=checkRanges[i].value;
/* write three code points */
U16_APPEND_UNSAFE(s, length, prevCP); /* start of the range */
values[countValues++]=value;
c=checkRanges[i].limit;
prevCP=(prevCP+c)/2; /* middle of the range */
U16_APPEND_UNSAFE(s, length, prevCP);
values[countValues++]=value;
prevCP=c;
--c; /* end of the range */
U16_APPEND_UNSAFE(s, length, c);
values[countValues++]=value;
}
limit=s+length;
/* try forward */
p=s;
i=0;
while(p<limit) {
sIndex=(int32_t)(p-s);
U16_NEXT(s, sIndex, length, c2);
c=0x33;
if(valueBits==UTRIE2_16_VALUE_BITS) {
UTRIE2_U16_NEXT16(trie, p, limit, c, value);
} else {
UTRIE2_U16_NEXT32(trie, p, limit, c, value);
}
if(value!=values[i]) {
log_err("error: wrong value from UTRIE2_NEXT(%s)(U+%04lx): 0x%lx instead of 0x%lx\n",
testName, (long)c, (long)value, (long)values[i]);
}
if(c!=c2) {
log_err("error: wrong code point from UTRIE2_NEXT(%s): U+%04lx != U+%04lx\n",
testName, (long)c, (long)c2);
continue;
}
++i;
}
/* try backward */
p=limit;
i=countValues;
while(s<p) {
--i;
sIndex=(int32_t)(p-s);
U16_PREV(s, 0, sIndex, c2);
c=0x33;
if(valueBits==UTRIE2_16_VALUE_BITS) {
UTRIE2_U16_PREV16(trie, s, p, c, value);
} else {
UTRIE2_U16_PREV32(trie, s, p, c, value);
}
if(value!=values[i]) {
log_err("error: wrong value from UTRIE2_PREV(%s)(U+%04lx): 0x%lx instead of 0x%lx\n",
testName, (long)c, (long)value, (long)values[i]);
}
if(c!=c2) {
log_err("error: wrong code point from UTRIE2_PREV(%s): U+%04lx != U+%04lx\n",
testName, c, c2);
}
}
}
static void
testTrieUTF8(const char *testName,
const UTrie2 *trie, UTrie2ValueBits valueBits,
const CheckRange checkRanges[], int32_t countCheckRanges) {
// Note: The byte sequence comments refer to the original UTF-8 definition.
// Starting with ICU 60, any sequence that is not a prefix of a valid one
// is treated as multiple single-byte errors.
// For testing, we only rely on U8_... and UTrie2 UTF-8 macros
// iterating consistently.
static const uint8_t illegal[]={
0xc0, 0x80, /* non-shortest U+0000 */
0xc1, 0xbf, /* non-shortest U+007f */
0xc2, /* truncated */
0xe0, 0x90, 0x80, /* non-shortest U+0400 */
0xe0, 0xa0, /* truncated */
0xed, 0xa0, 0x80, /* lead surrogate U+d800 */
0xed, 0xbf, 0xbf, /* trail surrogate U+dfff */
0xf0, 0x8f, 0xbf, 0xbf, /* non-shortest U+ffff */
0xf0, 0x90, 0x80, /* truncated */
0xf4, 0x90, 0x80, 0x80, /* beyond-Unicode U+110000 */
0xf8, 0x80, 0x80, 0x80, /* truncated */
0xf8, 0x80, 0x80, 0x80, 0x80, /* 5-byte UTF-8 */
0xfd, 0xbf, 0xbf, 0xbf, 0xbf, /* truncated */
0xfd, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, /* 6-byte UTF-8 */
0xfe,
0xff
};
uint8_t s[600];
uint32_t values[200];
const uint8_t *p, *limit;
uint32_t initialValue, errorValue;
uint32_t value, bytes;
UChar32 prevCP, c;
int32_t i, countSpecials, length, countValues;
int32_t prev8, i8;
countSpecials=getSpecialValues(checkRanges, countCheckRanges, &initialValue, &errorValue);
/* write a string */
prevCP=0;
length=countValues=0;
/* first a couple of trail bytes in lead position */
s[length++]=0x80;
values[countValues++]=errorValue;
s[length++]=0xbf;
values[countValues++]=errorValue;
prev8=i8=0;
for(i=countSpecials; i<countCheckRanges; ++i) {
value=checkRanges[i].value;
/* write three legal (or surrogate) code points */
U8_APPEND_UNSAFE(s, length, prevCP); /* start of the range */
if(U_IS_SURROGATE(prevCP)) {
// A surrogate byte sequence counts as 3 single-byte errors.
values[countValues++]=errorValue;
values[countValues++]=errorValue;
values[countValues++]=errorValue;
} else {
values[countValues++]=value;
}
c=checkRanges[i].limit;
prevCP=(prevCP+c)/2; /* middle of the range */
U8_APPEND_UNSAFE(s, length, prevCP);
if(U_IS_SURROGATE(prevCP)) {
// A surrogate byte sequence counts as 3 single-byte errors.
values[countValues++]=errorValue;
values[countValues++]=errorValue;
values[countValues++]=errorValue;
} else {
values[countValues++]=value;
}
prevCP=c;
--c; /* end of the range */
U8_APPEND_UNSAFE(s, length, c);
if(U_IS_SURROGATE(c)) {
// A surrogate byte sequence counts as 3 single-byte errors.
values[countValues++]=errorValue;
values[countValues++]=errorValue;
values[countValues++]=errorValue;
} else {
values[countValues++]=value;
}
/* write an illegal byte sequence */
if(i8<(int32_t)sizeof(illegal)) {
U8_FWD_1(illegal, i8, sizeof(illegal));
while(prev8<i8) {
s[length++]=illegal[prev8++];
}
values[countValues++]=errorValue;
}
}
/* write the remaining illegal byte sequences */
while(i8<(int32_t)sizeof(illegal)) {
U8_FWD_1(illegal, i8, sizeof(illegal));
while(prev8<i8) {
s[length++]=illegal[prev8++];
}
values[countValues++]=errorValue;
}
limit=s+length;
/* try forward */
p=s;
i=0;
while(p<limit) {
prev8=i8=(int32_t)(p-s);
U8_NEXT(s, i8, length, c);
if(valueBits==UTRIE2_16_VALUE_BITS) {
UTRIE2_U8_NEXT16(trie, p, limit, value);
} else {
UTRIE2_U8_NEXT32(trie, p, limit, value);
}
bytes=0;
if(value!=values[i] || i8!=(p-s)) {
int32_t k=prev8;
while(k<i8) {
bytes=(bytes<<8)|s[k++];
}
}
if(value!=values[i]) {
log_err("error: wrong value from UTRIE2_U8_NEXT(%s)(from %d %lx->U+%04lx) (read %d bytes): "
"0x%lx instead of 0x%lx\n",
testName, (int)prev8, (unsigned long)bytes, (long)c, (int)((p-s)-prev8),
(long)value, (long)values[i]);
}
if(i8!=(p-s)) {
log_err("error: wrong end index from UTRIE2_U8_NEXT(%s)(from %d %lx->U+%04lx): %ld != %ld\n",
testName, (int)prev8, (unsigned long)bytes, (long)c, (long)(p-s), (long)i8);
continue;
}
++i;
}
/* try backward */
p=limit;
i=countValues;
while(s<p) {
--i;
prev8=i8=(int32_t)(p-s);
U8_PREV(s, 0, i8, c);
if(valueBits==UTRIE2_16_VALUE_BITS) {
UTRIE2_U8_PREV16(trie, s, p, value);
} else {
UTRIE2_U8_PREV32(trie, s, p, value);
}
bytes=0;
if(value!=values[i] || i8!=(p-s)) {
int32_t k=i8;
while(k<prev8) {
bytes=(bytes<<8)|s[k++];
}
}
if(value!=values[i]) {
log_err("error: wrong value from UTRIE2_U8_PREV(%s)(from %d %lx->U+%04lx) (read %d bytes): "
": 0x%lx instead of 0x%lx\n",
testName, (int)prev8, (unsigned long)bytes, (long)c, (int)(prev8-(p-s)),
(long)value, (long)values[i]);
}
if(i8!=(p-s)) {
log_err("error: wrong end index from UTRIE2_U8_PREV(%s)(from %d %lx->U+%04lx): %ld != %ld\n",
testName, (int)prev8, (unsigned long)bytes, (long)c, (long)(p-s), (long)i8);
continue;
}
}
}
static void
testFrozenTrie(const char *testName,
UTrie2 *trie, UTrie2ValueBits valueBits,
const CheckRange checkRanges[], int32_t countCheckRanges) {
UErrorCode errorCode;
uint32_t value, value2;
if(!utrie2_isFrozen(trie)) {
log_err("error: utrie2_isFrozen(frozen %s) returned false (not frozen)\n",
testName);
return;
}
testTrieGetters(testName, trie, valueBits, checkRanges, countCheckRanges);
testTrieEnum(testName, trie, checkRanges, countCheckRanges);
testTrieUTF16(testName, trie, valueBits, checkRanges, countCheckRanges);
testTrieUTF8(testName, trie, valueBits, checkRanges, countCheckRanges);
errorCode=U_ZERO_ERROR;
value=utrie2_get32(trie, 1);
utrie2_set32(trie, 1, 234, &errorCode);
value2=utrie2_get32(trie, 1);
if(errorCode!=U_NO_WRITE_PERMISSION || value2!=value) {
log_err("error: utrie2_set32(frozen %s) failed: it set %s != U_NO_WRITE_PERMISSION\n",
testName, u_errorName(errorCode));
return;
}
errorCode=U_ZERO_ERROR;
utrie2_setRange32(trie, 1, 5, 234, true, &errorCode);
value2=utrie2_get32(trie, 1);
if(errorCode!=U_NO_WRITE_PERMISSION || value2!=value) {
log_err("error: utrie2_setRange32(frozen %s) failed: it set %s != U_NO_WRITE_PERMISSION\n",
testName, u_errorName(errorCode));
return;
}
errorCode=U_ZERO_ERROR;
value=utrie2_get32FromLeadSurrogateCodeUnit(trie, 0xd801);
utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xd801, 234, &errorCode);
value2=utrie2_get32FromLeadSurrogateCodeUnit(trie, 0xd801);
if(errorCode!=U_NO_WRITE_PERMISSION || value2!=value) {
log_err("error: utrie2_set32ForLeadSurrogateCodeUnit(frozen %s) failed: "
"it set %s != U_NO_WRITE_PERMISSION\n",
testName, u_errorName(errorCode));
return;
}
}
static void
testNewTrie(const char *testName, const UTrie2 *trie,
const CheckRange checkRanges[], int32_t countCheckRanges) {
/* The valueBits are ignored for an unfrozen trie. */
testTrieGetters(testName, trie, UTRIE2_COUNT_VALUE_BITS, checkRanges, countCheckRanges);
testTrieEnum(testName, trie, checkRanges, countCheckRanges);
}
static void
testTrieSerialize(const char *testName,
UTrie2 *trie, UTrie2ValueBits valueBits,
UBool withSwap,
const CheckRange checkRanges[], int32_t countCheckRanges) {
uint32_t storage[10000];
int32_t length1, length2, length3;
UTrie2ValueBits otherValueBits;
UErrorCode errorCode;
/* clone the trie so that the caller can reuse the original */
errorCode=U_ZERO_ERROR;
trie=utrie2_clone(trie, &errorCode);
if(U_FAILURE(errorCode)) {
log_err("error: utrie2_clone(unfrozen %s) failed - %s\n",
testName, u_errorName(errorCode));
return;
}
/*
* This is not a loop, but simply a block that we can exit with "break"
* when something goes wrong.
*/
do {
errorCode=U_ZERO_ERROR;
utrie2_serialize(trie, storage, sizeof(storage), &errorCode);
if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
log_err("error: utrie2_serialize(unfrozen %s) set %s != U_ILLEGAL_ARGUMENT_ERROR\n",
testName, u_errorName(errorCode));
break;
}
errorCode=U_ZERO_ERROR;
utrie2_freeze(trie, valueBits, &errorCode);
if(U_FAILURE(errorCode) || !utrie2_isFrozen(trie)) {
log_err("error: utrie2_freeze(%s) failed: %s isFrozen: %d\n",
testName, u_errorName(errorCode), utrie2_isFrozen(trie));
break;
}
otherValueBits= valueBits==UTRIE2_16_VALUE_BITS ? UTRIE2_32_VALUE_BITS : UTRIE2_16_VALUE_BITS;
utrie2_freeze(trie, otherValueBits, &errorCode);
if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
log_err("error: utrie2_freeze(already-frozen with other valueBits %s) "
"set %s != U_ILLEGAL_ARGUMENT_ERROR\n",
testName, u_errorName(errorCode));
break;
}
errorCode=U_ZERO_ERROR;
if(withSwap) {
/* clone a frozen trie */
UTrie2 *clone=utrie2_clone(trie, &errorCode);
if(U_FAILURE(errorCode)) {
log_err("error: cloning a frozen UTrie2 failed (%s) - %s\n",
testName, u_errorName(errorCode));
errorCode=U_ZERO_ERROR; /* continue with the original */
} else {
utrie2_close(trie);
trie=clone;
}
}
length1=utrie2_serialize(trie, NULL, 0, &errorCode);
if(errorCode!=U_BUFFER_OVERFLOW_ERROR) {
log_err("error: utrie2_serialize(%s) preflighting set %s != U_BUFFER_OVERFLOW_ERROR\n",
testName, u_errorName(errorCode));
break;
}
errorCode=U_ZERO_ERROR;
length2=utrie2_serialize(trie, storage, sizeof(storage), &errorCode);
if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
log_err("error: utrie2_serialize(%s) needs more memory\n", testName);
break;
}
if(U_FAILURE(errorCode)) {
log_err("error: utrie2_serialize(%s) failed: %s\n", testName, u_errorName(errorCode));
break;
}
if(length1!=length2) {
log_err("error: trie serialization (%s) lengths different: "
"preflight vs. serialize\n", testName);
break;
}
testFrozenTrie(testName, trie, valueBits, checkRanges, countCheckRanges);
utrie2_close(trie);
trie=NULL;
if(withSwap) {
uint32_t swapped[10000];
int32_t swappedLength;
UDataSwapper *ds;
/* swap to opposite-endian */
uprv_memset(swapped, 0x55, length2);
ds=udata_openSwapper(U_IS_BIG_ENDIAN, U_CHARSET_FAMILY,
!U_IS_BIG_ENDIAN, U_CHARSET_FAMILY, &errorCode);
swappedLength=utrie2_swap(ds, storage, -1, NULL, &errorCode);
if(U_FAILURE(errorCode) || swappedLength!=length2) {
log_err("error: utrie2_swap(%s to OE preflighting) failed (%s) "
"or before/after lengths different\n",
testName, u_errorName(errorCode));
udata_closeSwapper(ds);
break;
}
swappedLength=utrie2_swap(ds, storage, length2, swapped, &errorCode);
udata_closeSwapper(ds);
if(U_FAILURE(errorCode) || swappedLength!=length2) {
log_err("error: utrie2_swap(%s to OE) failed (%s) or before/after lengths different\n",
testName, u_errorName(errorCode));
break;
}
/* swap back to platform-endian */
uprv_memset(storage, 0xaa, length2);
ds=udata_openSwapper(!U_IS_BIG_ENDIAN, U_CHARSET_FAMILY,
U_IS_BIG_ENDIAN, U_CHARSET_FAMILY, &errorCode);
swappedLength=utrie2_swap(ds, swapped, -1, NULL, &errorCode);
if(U_FAILURE(errorCode) || swappedLength!=length2) {
log_err("error: utrie2_swap(%s to PE preflighting) failed (%s) "
"or before/after lengths different\n",
testName, u_errorName(errorCode));
udata_closeSwapper(ds);
break;
}
swappedLength=utrie2_swap(ds, swapped, length2, storage, &errorCode);
udata_closeSwapper(ds);
if(U_FAILURE(errorCode) || swappedLength!=length2) {
log_err("error: utrie2_swap(%s to PE) failed (%s) or before/after lengths different\n",
testName, u_errorName(errorCode));
break;
}
}
trie=utrie2_openFromSerialized(valueBits, storage, length2, &length3, &errorCode);
if(U_FAILURE(errorCode)) {
log_err("error: utrie2_openFromSerialized(%s) failed, %s\n", testName, u_errorName(errorCode));
break;
}
if((valueBits==UTRIE2_16_VALUE_BITS)!=(trie->data32==NULL)) {
log_err("error: trie serialization (%s) did not preserve 32-bitness\n", testName);
break;
}
if(length2!=length3) {
log_err("error: trie serialization (%s) lengths different: "
"serialize vs. unserialize\n", testName);
break;
}
/* overwrite the storage that is not supposed to be needed */
uprv_memset((char *)storage+length3, 0xfa, (int32_t)(sizeof(storage)-length3));
utrie2_freeze(trie, valueBits, &errorCode);
if(U_FAILURE(errorCode) || !utrie2_isFrozen(trie)) {
log_err("error: utrie2_freeze(unserialized %s) failed: %s isFrozen: %d\n",
testName, u_errorName(errorCode), utrie2_isFrozen(trie));
break;
}
utrie2_freeze(trie, otherValueBits, &errorCode);
if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR) {
log_err("error: utrie2_freeze(unserialized with other valueBits %s) "
"set %s != U_ILLEGAL_ARGUMENT_ERROR\n",
testName, u_errorName(errorCode));
break;
}
errorCode=U_ZERO_ERROR;
if(withSwap) {
/* clone an unserialized trie */
UTrie2 *clone=utrie2_clone(trie, &errorCode);
if(U_FAILURE(errorCode)) {
log_err("error: utrie2_clone(unserialized %s) failed - %s\n",
testName, u_errorName(errorCode));
errorCode=U_ZERO_ERROR;
/* no need to break: just test the original trie */
} else {
utrie2_close(trie);
trie=clone;
uprv_memset(storage, 0, sizeof(storage));
}
}
testFrozenTrie(testName, trie, valueBits, checkRanges, countCheckRanges);
{
/* clone-as-thawed an unserialized trie */
UTrie2 *clone=utrie2_cloneAsThawed(trie, &errorCode);
if(U_FAILURE(errorCode) || utrie2_isFrozen(clone)) {
log_err("error: utrie2_cloneAsThawed(unserialized %s) failed - "
"%s (isFrozen: %d)\n",
testName, u_errorName(errorCode), clone!=NULL && utrie2_isFrozen(trie));
break;
} else {
utrie2_close(trie);
trie=clone;
}
}
{
uint32_t value, value2;
value=utrie2_get32(trie, 0xa1);
utrie2_set32(trie, 0xa1, 789, &errorCode);
value2=utrie2_get32(trie, 0xa1);
utrie2_set32(trie, 0xa1, value, &errorCode);
if(U_FAILURE(errorCode) || value2!=789) {
log_err("error: modifying a cloneAsThawed UTrie2 (%s) failed - %s\n",
testName, u_errorName(errorCode));
}
}
testNewTrie(testName, trie, checkRanges, countCheckRanges);
} while(0);
utrie2_close(trie);
}
static UTrie2 *
testTrieSerializeAllValueBits(const char *testName,
UTrie2 *trie, UBool withClone,
const CheckRange checkRanges[], int32_t countCheckRanges) {
char name[40];
/* verify that all the expected values are in the unfrozen trie */
testNewTrie(testName, trie, checkRanges, countCheckRanges);
/*
* Test with both valueBits serializations,
* and that utrie2_serialize() can be called multiple times.
*/
uprv_strcpy(name, testName);
uprv_strcat(name, ".16");
testTrieSerialize(name, trie,
UTRIE2_16_VALUE_BITS, withClone,
checkRanges, countCheckRanges);
if(withClone) {
/*
* try cloning after the first serialization;
* clone-as-thawed just to sometimes try it on an unfrozen trie
*/
UErrorCode errorCode=U_ZERO_ERROR;
UTrie2 *clone=utrie2_cloneAsThawed(trie, &errorCode);
if(U_FAILURE(errorCode)) {
log_err("error: utrie2_cloneAsThawed(%s) after serialization failed - %s\n",
testName, u_errorName(errorCode));
} else {
utrie2_close(trie);
trie=clone;
testNewTrie(testName, trie, checkRanges, countCheckRanges);
}
}
uprv_strcpy(name, testName);
uprv_strcat(name, ".32");
testTrieSerialize(name, trie,
UTRIE2_32_VALUE_BITS, withClone,
checkRanges, countCheckRanges);
return trie; /* could be the clone */
}
static UTrie2 *
makeTrieWithRanges(const char *testName, UBool withClone,
const SetRange setRanges[], int32_t countSetRanges,
const CheckRange checkRanges[], int32_t countCheckRanges) {
UTrie2 *trie;
uint32_t initialValue, errorValue;
uint32_t value;
UChar32 start, limit;
int32_t i;
UErrorCode errorCode;
UBool overwrite;
log_verbose("\ntesting Trie '%s'\n", testName);
errorCode=U_ZERO_ERROR;
getSpecialValues(checkRanges, countCheckRanges, &initialValue, &errorValue);
trie=utrie2_open(initialValue, errorValue, &errorCode);
if(U_FAILURE(errorCode)) {
log_err("error: utrie2_open(%s) failed: %s\n", testName, u_errorName(errorCode));
return NULL;
}
/* set values from setRanges[] */
for(i=0; i<countSetRanges; ++i) {
if(withClone && i==countSetRanges/2) {
/* switch to a clone in the middle of setting values */
UTrie2 *clone=utrie2_clone(trie, &errorCode);
if(U_FAILURE(errorCode)) {
log_err("error: utrie2_clone(%s) failed - %s\n",
testName, u_errorName(errorCode));
errorCode=U_ZERO_ERROR; /* continue with the original */
} else {
utrie2_close(trie);
trie=clone;
}
}
start=setRanges[i].start;
limit=setRanges[i].limit;
value=setRanges[i].value;
overwrite=setRanges[i].overwrite;
if((limit-start)==1 && overwrite) {
utrie2_set32(trie, start, value, &errorCode);
} else {
utrie2_setRange32(trie, start, limit-1, value, overwrite, &errorCode);
}
}
/* set some values for lead surrogate code units */
utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xd800, 90, &errorCode);
utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xd999, 94, &errorCode);
utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xdbff, 99, &errorCode);
if(U_SUCCESS(errorCode)) {
return trie;
} else {
log_err("error: setting values into a trie (%s) failed - %s\n",
testName, u_errorName(errorCode));
utrie2_close(trie);
return NULL;
}
}
static void
testTrieRanges(const char *testName, UBool withClone,
const SetRange setRanges[], int32_t countSetRanges,
const CheckRange checkRanges[], int32_t countCheckRanges) {
UTrie2 *trie=makeTrieWithRanges(testName, withClone,
setRanges, countSetRanges,
checkRanges, countCheckRanges);
if(trie!=NULL) {
trie=testTrieSerializeAllValueBits(testName, trie, withClone,
checkRanges, countCheckRanges);
utrie2_close(trie);
}
}
/* test data ----------------------------------------------------------------*/
/* set consecutive ranges, even with value 0 */
static const SetRange
setRanges1[]={
{ 0, 0x40, 0, false },
{ 0x40, 0xe7, 0x1234, false },
{ 0xe7, 0x3400, 0, false },
{ 0x3400, 0x9fa6, 0x6162, false },
{ 0x9fa6, 0xda9e, 0x3132, false },
{ 0xdada, 0xeeee, 0x87ff, false },
{ 0xeeee, 0x11111, 1, false },
{ 0x11111, 0x44444, 0x6162, false },
{ 0x44444, 0x60003, 0, false },
{ 0xf0003, 0xf0004, 0xf, false },
{ 0xf0004, 0xf0006, 0x10, false },
{ 0xf0006, 0xf0007, 0x11, false },
{ 0xf0007, 0xf0040, 0x12, false },
{ 0xf0040, 0x110000, 0, false }
};
static const CheckRange
checkRanges1[]={
{ 0, 0 },
{ 0x40, 0 },
{ 0xe7, 0x1234 },
{ 0x3400, 0 },
{ 0x9fa6, 0x6162 },
{ 0xda9e, 0x3132 },
{ 0xdada, 0 },
{ 0xeeee, 0x87ff },
{ 0x11111, 1 },
{ 0x44444, 0x6162 },
{ 0xf0003, 0 },
{ 0xf0004, 0xf },
{ 0xf0006, 0x10 },
{ 0xf0007, 0x11 },
{ 0xf0040, 0x12 },
{ 0x110000, 0 }
};
/* set some interesting overlapping ranges */
static const SetRange
setRanges2[]={
{ 0x21, 0x7f, 0x5555, true },
{ 0x2f800, 0x2fedc, 0x7a, true },
{ 0x72, 0xdd, 3, true },
{ 0xdd, 0xde, 4, false },
{ 0x201, 0x240, 6, true }, /* 3 consecutive blocks with the same pattern but */
{ 0x241, 0x280, 6, true }, /* discontiguous value ranges, testing utrie2_enum() */
{ 0x281, 0x2c0, 6, true },
{ 0x2f987, 0x2fa98, 5, true },
{ 0x2f777, 0x2f883, 0, true },
{ 0x2f900, 0x2ffaa, 1, false },
{ 0x2ffaa, 0x2ffab, 2, true },
{ 0x2ffbb, 0x2ffc0, 7, true }
};
static const CheckRange
checkRanges2[]={
{ 0, 0 },
{ 0x21, 0 },
{ 0x72, 0x5555 },
{ 0xdd, 3 },
{ 0xde, 4 },
{ 0x201, 0 },
{ 0x240, 6 },
{ 0x241, 0 },
{ 0x280, 6 },
{ 0x281, 0 },
{ 0x2c0, 6 },
{ 0x2f883, 0 },
{ 0x2f987, 0x7a },
{ 0x2fa98, 5 },
{ 0x2fedc, 0x7a },
{ 0x2ffaa, 1 },
{ 0x2ffab, 2 },
{ 0x2ffbb, 0 },
{ 0x2ffc0, 7 },
{ 0x110000, 0 }
};
static const CheckRange
checkRanges2_d800[]={
{ 0x10000, 0 },
{ 0x10400, 0 }
};
static const CheckRange
checkRanges2_d87e[]={
{ 0x2f800, 6 },
{ 0x2f883, 0 },
{ 0x2f987, 0x7a },
{ 0x2fa98, 5 },
{ 0x2fc00, 0x7a }
};
static const CheckRange
checkRanges2_d87f[]={
{ 0x2fc00, 0 },
{ 0x2fedc, 0x7a },
{ 0x2ffaa, 1 },
{ 0x2ffab, 2 },
{ 0x2ffbb, 0 },
{ 0x2ffc0, 7 },
{ 0x30000, 0 }
};
static const CheckRange
checkRanges2_dbff[]={
{ 0x10fc00, 0 },
{ 0x110000, 0 }
};
/* use a non-zero initial value */
static const SetRange
setRanges3[]={
{ 0x31, 0xa4, 1, false },
{ 0x3400, 0x6789, 2, false },
{ 0x8000, 0x89ab, 9, true },
{ 0x9000, 0xa000, 4, true },
{ 0xabcd, 0xbcde, 3, true },
{ 0x55555, 0x110000, 6, true }, /* highStart<U+ffff with non-initialValue */
{ 0xcccc, 0x55555, 6, true }
};
static const CheckRange
checkRanges3[]={
{ 0, 9 }, /* non-zero initialValue */
{ 0x31, 9 },
{ 0xa4, 1 },
{ 0x3400, 9 },
{ 0x6789, 2 },
{ 0x9000, 9 },
{ 0xa000, 4 },
{ 0xabcd, 9 },
{ 0xbcde, 3 },
{ 0xcccc, 9 },
{ 0x110000, 6 }
};
/* empty or single-value tries, testing highStart==0 */
static const SetRange
setRangesEmpty[]={
{ 0, 0, 0, false }, /* need some values for it to compile */
};
static const CheckRange
checkRangesEmpty[]={
{ 0, 3 },
{ 0x110000, 3 }
};
static const SetRange
setRangesSingleValue[]={
{ 0, 0x110000, 5, true },
};
static const CheckRange
checkRangesSingleValue[]={
{ 0, 3 },
{ 0x110000, 5 }
};
static void
TrieTest(void) {
testTrieRanges("set1", false,
setRanges1, UPRV_LENGTHOF(setRanges1),
checkRanges1, UPRV_LENGTHOF(checkRanges1));
testTrieRanges("set2-overlap", false,
setRanges2, UPRV_LENGTHOF(setRanges2),
checkRanges2, UPRV_LENGTHOF(checkRanges2));
testTrieRanges("set3-initial-9", false,
setRanges3, UPRV_LENGTHOF(setRanges3),
checkRanges3, UPRV_LENGTHOF(checkRanges3));
testTrieRanges("set-empty", false,
setRangesEmpty, 0,
checkRangesEmpty, UPRV_LENGTHOF(checkRangesEmpty));
testTrieRanges("set-single-value", false,
setRangesSingleValue, UPRV_LENGTHOF(setRangesSingleValue),
checkRangesSingleValue, UPRV_LENGTHOF(checkRangesSingleValue));
testTrieRanges("set2-overlap.withClone", true,
setRanges2, UPRV_LENGTHOF(setRanges2),
checkRanges2, UPRV_LENGTHOF(checkRanges2));
}
static void
EnumNewTrieForLeadSurrogateTest(void) {
static const char *const testName="enum-for-lead";
UTrie2 *trie=makeTrieWithRanges(testName, false,
setRanges2, UPRV_LENGTHOF(setRanges2),
checkRanges2, UPRV_LENGTHOF(checkRanges2));
while(trie!=NULL) {
const CheckRange *checkRanges;
checkRanges=checkRanges2_d800+1;
utrie2_enumForLeadSurrogate(trie, 0xd800,
testEnumValue, testEnumRange,
&checkRanges);
checkRanges=checkRanges2_d87e+1;
utrie2_enumForLeadSurrogate(trie, 0xd87e,
testEnumValue, testEnumRange,
&checkRanges);
checkRanges=checkRanges2_d87f+1;
utrie2_enumForLeadSurrogate(trie, 0xd87f,
testEnumValue, testEnumRange,
&checkRanges);
checkRanges=checkRanges2_dbff+1;
utrie2_enumForLeadSurrogate(trie, 0xdbff,
testEnumValue, testEnumRange,
&checkRanges);
if(!utrie2_isFrozen(trie)) {
UErrorCode errorCode=U_ZERO_ERROR;
utrie2_freeze(trie, UTRIE2_16_VALUE_BITS, &errorCode);
if(U_FAILURE(errorCode)) {
log_err("error: utrie2_freeze(%s) failed\n", testName);
utrie2_close(trie);
return;
}
} else {
utrie2_close(trie);
break;
}
}
}
/* test utrie2_openDummy() -------------------------------------------------- */
static void
dummyTest(UTrie2ValueBits valueBits) {
CheckRange
checkRanges[]={
{ -1, 0 },
{ 0, 0 },
{ 0x110000, 0 }
};
UTrie2 *trie;
UErrorCode errorCode;
const char *testName;
uint32_t initialValue, errorValue;
if(valueBits==UTRIE2_16_VALUE_BITS) {
testName="dummy.16";
initialValue=0x313;
errorValue=0xaffe;
} else {
testName="dummy.32";
initialValue=0x01234567;
errorValue=0x89abcdef;
}
checkRanges[0].value=errorValue;
checkRanges[1].value=checkRanges[2].value=initialValue;
errorCode=U_ZERO_ERROR;
trie=utrie2_openDummy(valueBits, initialValue, errorValue, &errorCode);
if(U_FAILURE(errorCode)) {
log_err("utrie2_openDummy(valueBits=%d) failed - %s\n", valueBits, u_errorName(errorCode));
return;
}
testFrozenTrie(testName, trie, valueBits, checkRanges, UPRV_LENGTHOF(checkRanges));
utrie2_close(trie);
}
static void
DummyTrieTest(void) {
dummyTest(UTRIE2_16_VALUE_BITS);
dummyTest(UTRIE2_32_VALUE_BITS);
}
/* test builder memory management ------------------------------------------- */
static void
FreeBlocksTest(void) {
static const CheckRange
checkRanges[]={
{ 0, 1 },
{ 0x740, 1 },
{ 0x780, 2 },
{ 0x880, 3 },
{ 0x110000, 1 }
};
static const char *const testName="free-blocks";
UTrie2 *trie;
int32_t i;
UErrorCode errorCode;
errorCode=U_ZERO_ERROR;
trie=utrie2_open(1, 0xbad, &errorCode);
if(U_FAILURE(errorCode)) {
log_err("error: utrie2_open(%s) failed: %s\n", testName, u_errorName(errorCode));
return;
}
/*
* Repeatedly set overlapping same-value ranges to stress the free-data-block management.
* If it fails, it will overflow the data array.
*/
for(i=0; i<(0x120000>>UTRIE2_SHIFT_2)/2; ++i) {
utrie2_setRange32(trie, 0x740, 0x840-1, 1, true, &errorCode);
utrie2_setRange32(trie, 0x780, 0x880-1, 1, true, &errorCode);
utrie2_setRange32(trie, 0x740, 0x840-1, 2, true, &errorCode);
utrie2_setRange32(trie, 0x780, 0x880-1, 3, true, &errorCode);
}
/* make blocks that will be free during compaction */
utrie2_setRange32(trie, 0x1000, 0x3000-1, 2, true, &errorCode);
utrie2_setRange32(trie, 0x2000, 0x4000-1, 3, true, &errorCode);
utrie2_setRange32(trie, 0x1000, 0x4000-1, 1, true, &errorCode);
/* set some values for lead surrogate code units */
utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xd800, 90, &errorCode);
utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xd999, 94, &errorCode);
utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xdbff, 99, &errorCode);
if(U_FAILURE(errorCode)) {
log_err("error: setting lots of ranges into a trie (%s) failed - %s\n",
testName, u_errorName(errorCode));
utrie2_close(trie);
return;
}
trie=testTrieSerializeAllValueBits(testName, trie, false,
checkRanges, UPRV_LENGTHOF(checkRanges));
utrie2_close(trie);
}
static void
GrowDataArrayTest(void) {
static const CheckRange
checkRanges[]={
{ 0, 1 },
{ 0x720, 2 },
{ 0x7a0, 3 },
{ 0x8a0, 4 },
{ 0x110000, 5 }
};
static const char *const testName="grow-data";
UTrie2 *trie;
int32_t i;
UErrorCode errorCode;
errorCode=U_ZERO_ERROR;
trie=utrie2_open(1, 0xbad, &errorCode);
if(U_FAILURE(errorCode)) {
log_err("error: utrie2_open(%s) failed: %s\n", testName, u_errorName(errorCode));
return;
}
/*
* Use utrie2_set32() not utrie2_setRange32() to write non-initialValue-data.
* Should grow/reallocate the data array to a sufficient length.
*/
for(i=0; i<0x1000; ++i) {
utrie2_set32(trie, i, 2, &errorCode);
}
for(i=0x720; i<0x1100; ++i) { /* some overlap */
utrie2_set32(trie, i, 3, &errorCode);
}
for(i=0x7a0; i<0x900; ++i) {
utrie2_set32(trie, i, 4, &errorCode);
}
for(i=0x8a0; i<0x110000; ++i) {
utrie2_set32(trie, i, 5, &errorCode);
}
for(i=0xd800; i<0xdc00; ++i) {
utrie2_set32ForLeadSurrogateCodeUnit(trie, i, 1, &errorCode);
}
/* set some values for lead surrogate code units */
utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xd800, 90, &errorCode);
utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xd999, 94, &errorCode);
utrie2_set32ForLeadSurrogateCodeUnit(trie, 0xdbff, 99, &errorCode);
if(U_FAILURE(errorCode)) {
log_err("error: setting lots of values into a trie (%s) failed - %s\n",
testName, u_errorName(errorCode));
utrie2_close(trie);
return;
}
trie=testTrieSerializeAllValueBits(testName, trie, false,
checkRanges, UPRV_LENGTHOF(checkRanges));
utrie2_close(trie);
}
/* versions 1 and 2 --------------------------------------------------------- */
static UNewTrie *
makeNewTrie1WithRanges(const char *testName,
const SetRange setRanges[], int32_t countSetRanges,
const CheckRange checkRanges[], int32_t countCheckRanges) {
UNewTrie *newTrie;
uint32_t initialValue, errorValue;
uint32_t value;
UChar32 start, limit;
int32_t i;
UErrorCode errorCode;
UBool overwrite, ok;
log_verbose("\ntesting Trie '%s'\n", testName);
errorCode=U_ZERO_ERROR;
getSpecialValues(checkRanges, countCheckRanges, &initialValue, &errorValue);
newTrie=utrie_open(NULL, NULL, 2000,
initialValue, initialValue,
false);
if(U_FAILURE(errorCode)) {
log_err("error: utrie_open(%s) failed: %s\n", testName, u_errorName(errorCode));
return NULL;
}
/* set values from setRanges[] */
ok=true;
for(i=0; i<countSetRanges; ++i) {
start=setRanges[i].start;
limit=setRanges[i].limit;
value=setRanges[i].value;
overwrite=setRanges[i].overwrite;
if((limit-start)==1 && overwrite) {
ok&=utrie_set32(newTrie, start, value);
} else {
ok&=utrie_setRange32(newTrie, start, limit, value, overwrite);
}
}
if(ok) {
return newTrie;
} else {
log_err("error: setting values into a trie1 (%s) failed\n", testName);
utrie_close(newTrie);
return NULL;
}
}
static void
testTrie2FromTrie1(const char *testName,
const SetRange setRanges[], int32_t countSetRanges,
const CheckRange checkRanges[], int32_t countCheckRanges) {
uint32_t memory1_16[3000], memory1_32[3000];
int32_t length16, length32;
UChar lead;
char name[40];
UNewTrie *newTrie1_16, *newTrie1_32;
UTrie trie1_16, trie1_32;
UTrie2 *trie2;
uint32_t initialValue, errorValue;
UErrorCode errorCode;
newTrie1_16=makeNewTrie1WithRanges(testName,
setRanges, countSetRanges,
checkRanges, countCheckRanges);
if(newTrie1_16==NULL) {
return;
}
newTrie1_32=utrie_clone(NULL, newTrie1_16, NULL, 0);
if(newTrie1_32==NULL) {
utrie_close(newTrie1_16);
return;
}
errorCode=U_ZERO_ERROR;
length16=utrie_serialize(newTrie1_16, memory1_16, sizeof(memory1_16),
NULL, true, &errorCode);
length32=utrie_serialize(newTrie1_32, memory1_32, sizeof(memory1_32),
NULL, false, &errorCode);
utrie_unserialize(&trie1_16, memory1_16, length16, &errorCode);
utrie_unserialize(&trie1_32, memory1_32, length32, &errorCode);
utrie_close(newTrie1_16);
utrie_close(newTrie1_32);
if(U_FAILURE(errorCode)) {
log_err("error: utrie_serialize or unserialize(%s) failed: %s\n",
testName, u_errorName(errorCode));
return;
}
getSpecialValues(checkRanges, countCheckRanges, &initialValue, &errorValue);
uprv_strcpy(name, testName);
uprv_strcat(name, ".16");
trie2=utrie2_fromUTrie(&trie1_16, errorValue, &errorCode);
if(U_SUCCESS(errorCode)) {
testFrozenTrie(name, trie2, UTRIE2_16_VALUE_BITS, checkRanges, countCheckRanges);
for(lead=0xd800; lead<0xdc00; ++lead) {
uint32_t value1, value2;
value1=UTRIE_GET16_FROM_LEAD(&trie1_16, lead);
value2=UTRIE2_GET16_FROM_U16_SINGLE_LEAD(trie2, lead);
if(value1!=value2) {
log_err("error: utrie2_fromUTrie(%s) wrong value %ld!=%ld "
"from lead surrogate code unit U+%04lx\n",
name, (long)value2, (long)value1, (long)lead);
break;
}
}
}
utrie2_close(trie2);
uprv_strcpy(name, testName);
uprv_strcat(name, ".32");
trie2=utrie2_fromUTrie(&trie1_32, errorValue, &errorCode);
if(U_SUCCESS(errorCode)) {
testFrozenTrie(name, trie2, UTRIE2_32_VALUE_BITS, checkRanges, countCheckRanges);
for(lead=0xd800; lead<0xdc00; ++lead) {
uint32_t value1, value2;
value1=UTRIE_GET32_FROM_LEAD(&trie1_32, lead);
value2=UTRIE2_GET32_FROM_U16_SINGLE_LEAD(trie2, lead);
if(value1!=value2) {
log_err("error: utrie2_fromUTrie(%s) wrong value %ld!=%ld "
"from lead surrogate code unit U+%04lx\n",
name, (long)value2, (long)value1, (long)lead);
break;
}
}
}
utrie2_close(trie2);
}
static void
Trie12ConversionTest(void) {
testTrie2FromTrie1("trie1->trie2",
setRanges2, UPRV_LENGTHOF(setRanges2),
checkRanges2, UPRV_LENGTHOF(checkRanges2));
}
void
addTrie2Test(TestNode** root) {
addTest(root, &TrieTest, "tsutil/trie2test/TrieTest");
addTest(root, &EnumNewTrieForLeadSurrogateTest,
"tsutil/trie2test/EnumNewTrieForLeadSurrogateTest");
addTest(root, &DummyTrieTest, "tsutil/trie2test/DummyTrieTest");
addTest(root, &FreeBlocksTest, "tsutil/trie2test/FreeBlocksTest");
addTest(root, &GrowDataArrayTest, "tsutil/trie2test/GrowDataArrayTest");
addTest(root, &Trie12ConversionTest, "tsutil/trie2test/Trie12ConversionTest");
}