mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-14 17:24:01 +00:00
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.
1437 lines
50 KiB
C
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");
|
|
}
|